【问题标题】:Python SQLite: database is lockedPython SQLite:数据库被锁定
【发布时间】:2011-02-14 00:15:18
【问题描述】:

我正在尝试这段代码:

import sqlite

connection = sqlite.connect('cache.db')
cur = connection.cursor()
cur.execute('''create table item
  (id integer primary key, itemno text unique,
        scancode text, descr text, price real)''')

connection.commit()
cur.close()

我发现了这个异常:

Traceback (most recent call last):
  File "cache_storage.py", line 7, in <module>
    scancode text, descr text, price real)''')
  File "/usr/lib/python2.6/dist-packages/sqlite/main.py", line 237, in execute
    self.con._begin()
  File "/usr/lib/python2.6/dist-packages/sqlite/main.py", line 503, in _begin
    self.db.execute("BEGIN")
_sqlite.OperationalError: database is locked

cache.db 的权限没问题。有什么想法吗?

【问题讨论】:

    标签: python sqlite pysqlite


    【解决方案1】:

    我假设您实际上正在使用 sqlite3,即使您的代码另有说明。以下是一些需要检查的事项:

    1. 文件上没有挂起的进程(unix:$ fuser cache.db 应该什么都不说)
    2. cache.db所在目录中没有cache.db-journal文件;这将表明一个没有正确清理的崩溃会话。
    3. 要求数据库外壳检查自身:$ sqlite3 cache.db "pragma integrity_check;"
    4. 备份数据库$ sqlite3 cache.db ".backup cache.db.bak"
    5. 删除 cache.db,因为其中可能没有任何内容(如果您只是在学习)并再次尝试您的代码
    6. 查看备份是否有效$ sqlite3 cache.db.bak ".schema"

    如果失败,请阅读 Things That Can Go WrongHow to Corrupt Your Database Files

    【讨论】:

    • 我保留这个答案,因为它通常很有用,但我的另一个答案可能是正确的。
    • 更好:添加您的其他答案作为第 7 件事要检查 ;)
    • 感谢您的回复。我在这个数据库中没有任何数据(cache.db 是 0 字节大小),所以没有必要备份它。 1) fuser 不输出任何内容 2) 启动前没有 db-journal 文件 3) sqlite3 cache.db "pragma integrity_check;"说好的 5) 我多次尝试删除和重命名 cache.db 文件;-) 现在我已经在另一台机器上测试了它,但在相同的操作系统 Ubuntu 9.10 服务器版本上,我得到了相同的结果。当我安装 python-sqlite 包时发生此错误。
    【解决方案2】:

    在你的连接调用中设置超时参数,如:

    connection = sqlite.connect('cache.db', timeout=10)
    

    【讨论】:

    • 看起来默认是 5 秒,每个 docs.python.org/2/library/sqlite3.html#sqlite3.connect
    • 当您的连接调用失败并显示“数据库已锁定”错误消息时,这是因为另一个连接已经在访问数据库。通过指定超时(在本例中为 timeout=10),您将给另一个线程时间来完成其事务并关闭连接,然后您的连接就能够继续进行。如果没有超时,连接尝试会立即失败。
    【解决方案3】:

    我知道这是旧的,但我仍然遇到问题,这是谷歌上的第一个链接。 OP 说他的问题是 .db 位于 SMB 共享上,这正是我的情况。我十分钟的研究表明这是sqlite3和smb之间的已知冲突;我发现了可以追溯到 2007 年的错误报告。

    我通过在 /etc/fstab 中的 smb 挂载行中添加“nobrl”选项解决了这个问题,该行现在看起来像这样:

    //SERVER/share /mnt/point cifs credentials=/path/to/.creds,sec=ntlm,nobrl 0 0
    

    此选项可防止您的 SMB 客户端向服务器发送字节范围锁定。我不太了解我的 SMB 协议细节,但我最好能说这个设置在多用户环境中最受关注,在这种环境中,其他人可能会尝试写入与您相同的数据库。至少对于家庭设置,我认为它足够安全。

    我的相关版本:

    • 薄荷 17.1 丽贝卡
    • SMB v4.1.6-Ubuntu
    • Python v3.4.0
    • SQLite v3.8.2
    • 网络共享托管在 Win12R2 服务器上

    【讨论】:

    • 我有同样的问题,它不适用于 SMB 共享。我尝试了添加 nobrl 的解决方案,但仍然出现相同的错误。本地化它工作正常。
    【解决方案4】:

    我显示“锁定”消息的原因实际上是因为我在我的 Mac 上打开了 SQLite3 IDE,这就是它被锁定的原因。我假设我在 IDE 中使用数据库并且没有保存更改,因此放置了一个锁。

    长话短说,检查数据库上没有未保存的更改,并且它没有在其他地方使用。

    【讨论】:

    • 这个咬我。 DB Browser SQLIte 中未保存的更改
    【解决方案5】:

    在 Linux 中你可以做类似的事情,例如,如果你的锁定文件是 development.db:

    $ fuser development.db 此命令将显示锁定文件的进程:

    development.db: 5430 只需终止进程...

    杀死 -9 5430 ...您的数据库将被解锁。

    【讨论】:

      【解决方案6】:

      原来问题的发生是因为 db 文件的路径实际上是 samba 挂载的目录。我移动了它,它开始工作了。

      【讨论】:

        【解决方案7】:

        这是一个同时访问的巧妙解决方法:

        while True:
            connection = sqlite3.connect('user.db', timeout=1)
            cursor = connection.cursor()
            try:
                cursor.execute("SELECT * FROM queue;")
                result = cursor.fetchall()
            except sqlite3.OperationalError:
                print("database locked")
            num_users = len(result)
        # ...
        

        【讨论】:

        • 你忘了continue吗?
        • 给他一个break
        • btw timeout=1 是多余的:在大多数情况下,默认超时 5 秒可能就足够了。
        【解决方案8】:

        因为这仍然是该问题的热门 Google 搜索结果,所以让我添加一个可能的原因。如果您正在编辑数据库结构并且尚未提交更改,则数据库将被锁定,直到您提交或恢复。

        (可能不常见,但我正在开发一个应用程序,因此代码和数据库正在同时开发)

        【讨论】:

          【解决方案9】:

          数据库被另一个正在写入的进程锁定。您必须等到另一个事务被提交。请参阅 connect() 的文档

          【讨论】:

            【解决方案10】:

            我使用 SQLite 遇到的数据库被锁定的一个可能原因是,当我尝试访问一个正在由一个应用程序写入并同时被另一个应用程序读取的行时。您可能希望在 SQLite 包装器中设置繁忙超时,该包装器将旋转并等待数据库空闲(在原始 c++ api 中,函数为 sqlite3_busy_timeout)。我发现在大多数情况下 300 毫秒就足够了。

            但根据您的帖子,我怀疑这是问题所在。请先尝试其他建议。

            【讨论】:

              【解决方案11】:
              1. 您的cache.db 当前正被另一个进程使用。
              2. 停止该过程并重试,它应该可以工作。

              【讨论】:

                【解决方案12】:

                您应该检查您的数据库是否没有运行 DBMS 管理和开发平台(如 pgAdmin),因为这可能是导致此错误的最常见原因。如果有 - 提交所做的更改,问题就消失了。

                【讨论】:

                  【解决方案13】:

                  我遇到了同样的问题:sqlite3.IntegrityError

                  正如许多答案中提到的,问题是连接没有正确关闭。

                  就我而言,我有 try except 块。我正在访问try 块中的数据库,当引发异常时,我想在except 块中执行其他操作。

                  try:
                      conn = sqlite3.connect(path)
                      cur = conn.cursor()
                      cur.execute('''INSERT INTO ...''')
                  except:
                      conn = sqlite3.connect(path)
                      cur = conn.cursor()
                      cur.execute('''DELETE FROM ...''')
                      cur.execute('''INSERT INTO ...''')
                  

                  但是,当引发异常时,来自try 块的连接关闭

                  我使用块内的with 语句解决了它。

                  try:
                      with sqlite3.connect(path) as conn:
                          cur = conn.cursor()
                          cur.execute('''INSERT INTO ...''')
                  except:
                      with sqlite3.connect(path) as conn:
                          cur = conn.cursor()
                          cur.execute('''DELETE FROM ...''')
                          cur.execute('''INSERT INTO ...''')
                  

                  【讨论】:

                  • 你什么时候commit
                  【解决方案14】:

                  哦,你的回溯泄露了它:你有一个版本冲突。当您的 python2.6 发行版中已经包含 sqlite3 并且不需要并且可能无法使用旧版本的 sqlite 时,您已经在本地 dist-packages 目录中安装了一些旧版本的 sqlite。第一次尝试:

                  $ python -c "import sqlite3"
                  

                  如果这没有给你错误,uninstall your dist-package:

                  easy_install -mxN sqlite
                  

                  然后在您的代码中使用import sqlite3,然后玩得开心。

                  【讨论】:

                  • 我检查了使用 sqlite3 并且它的工作方式不同。它创建 db-journal 文件并等待。然后再次“数据库被锁定”,而没有“3”的sqlite不会等待任何东西。
                  【解决方案15】:

                  我在使用 Pycharm 和最初由另一个用户提供给我的数据库时遇到了这个问题。

                  所以,这就是我的解决方法:

                  1. 关闭了 Pycharm 中与有问题的数据库一起操作的所有选项卡。
                  2. 从 Pycharm 右上角的红色方形按钮停止所有正在运行的进程。
                  3. 从目录中删除有问题的数据库。
                  4. 再次上传原始数据库。 它又奏效了。

                  【讨论】:

                    【解决方案16】:

                    我也有这个问题。我试图将数据输入数据库而不保存我在其中所做的更改。在我保存更改后

                    【讨论】:

                    • 对这类简短答案使用评论。如果您要回答任何解释性问题,请添加更多信息、站点示例并提供参考。
                    【解决方案17】:

                    在我的情况下,当很多并发进程试图读/写同一个表时,就会发生错误。我用 retry 来解决这个问题

                    def _retry_if_exception(exception):
                        return isinstance(exception, Exception)
                    
                    @retry(retry_on_exception=_retry_if_exception,
                           wait_random_min=1000,
                           wait_random_max=5000,
                           stop_max_attempt_number=5)
                    def execute(cmd, commit=True):
                       c.execute(cmd)
                       c.conn.commit()
                    

                    【讨论】:

                      【解决方案18】:

                      即使我只有一个作者和一个读者,我的问题是其中一个读取时间太长:超过了规定的 5 秒超时时间。所以作者超时并导致错误。

                      因此,从数据库中读取所有条目时要小心,尤其是从表的大小随时间增长的数据库中。

                      【讨论】:

                        【解决方案19】:

                        简单的解决方案:检查一次您是否在另一个窗口或另一个终端中打开了数据库。这也会锁定您的数据库。就我而言,我关闭了所有其他锁定数据库的终端(Pycharm 中的终端选项卡)。如果有一个终端使数据库处于打开状态,请检查 IDE 终端的每个选项卡。 exit() 所有终端都应该可以解锁数据库。

                        【讨论】:

                          【解决方案20】:

                          我发现这可以满足我的需要(线程锁定):

                          conn = sqlite3.connect(database, timeout=10)
                          

                          Docs

                          sqlite3.connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri])
                          

                          当一个数据库被多个连接访问,并且其中一个进程修改了数据库时,SQLite 数据库将被锁定,直到该事务被提交。 timeout 参数指定连接应该等待锁消失多长时间,直到引发异常。超时参数的默认值为 5.0(五秒)。

                          【讨论】:

                            【解决方案21】:

                            就我而言,“锁定”消息是由于我在 DB BROWSER(SQL LITE) 中所做的未保存更改而发生的,我必须保存它们,然后当我再次执行我的脚本时,问题已解决,希望这可以帮助像我这样的人。

                            【讨论】:

                              【解决方案22】:

                              只是发生在我身上的另一种可能性,我打开数据库两次,第一次打开阻止了第二次。检查你没有这样做。

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 2011-10-30
                                • 1970-01-01
                                • 1970-01-01
                                • 2011-08-05
                                • 2015-05-11
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                相关资源
                                最近更新 更多