Python SQLite: 数据库被锁定

69

我尝试了这段代码:

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的权限没问题。有什么想法吗?

23个回答

62

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

  1. 确保没有挂起的进程停留在该文件上(unix:$ fuser cache.db 应该什么也没有)
  2. 目录中不存在与cache.db同名的cache.db-journal文件;这表明会话崩溃后未被适当清理。
  3. 要求数据库shell进行自检:$ sqlite3 cache.db“pragma integrity_check;”
  4. 备份数据库:$ sqlite3 cache.db“.backup cache.db.bak”
  5. 删除cache.db,因为您可能里面什么都没有(如果您只是在学习),然后再次尝试您的代码
  6. 查看备份是否有效:$ sqlite3 cache.db.bak“.schema”

如果还有问题,请阅读可能出现的问题如何损坏您的数据库文件


我让这个答案保持原样,因为它通常是有用的,但我的另一个答案可能是正确的。 - msw
1
更好的做法是:将你的另一个答案添加为要检查的第七个事项 ;) - tzot
感谢您的回复。我在这个数据库中没有任何数据(cache.db大小为0字节),因此不需要备份它。 1)fuser不输出任何内容。 2)在启动之前没有db-journal文件。 3)sqlite3 cache.db“pragma integrity_check;”显示正常。 5)我尝试多次删除和重命名cache.db文件;-) 现在我已经在另一台机器上测试了它,但是在相同的Ubuntu 9.10服务器版操作系统上,我得到了相同的结果。当我安装python-sqlite包时会出现这个错误。 - Soid

60

在您的connect调用中设置超时参数,例如:

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

4
根据 https://docs.python.org/2/library/sqlite3.html#sqlite3.connect,似乎默认值为 5 秒。 - storm_m2138
4
当你尝试连接时出现“数据库已锁定”错误消息,这是因为另一个连接已经正在访问该数据库。通过指定超时时间(在本例中为timeout=10),你会给其他线程完成其事务并关闭连接的时间,然后你的连接才能继续进行。如果没有超时时间,连接尝试会立即失败。 - Anthony DeRosa

26

我知道这已经是老问题了,但我仍然遇到这个问题,而且这是Google上的第一个链接。原帖中提到他的问题是由于.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协议的详细信息,但据我所知,这个设置主要会在多用户环境中引起担忧,因为其他人可能正试图向与您相同的数据库写入数据。至少对于家庭设置而言,我认为是足够安全的。

我的相关版本:

  • Mint 17.1 Rebecca
  • SMB v4.1.6-Ubuntu
  • Python v3.4.0
  • SQLite v3.8.2
  • 网络共享托管在Win12R2服务器上

我遇到了相同的问题,它在SMB共享上无法工作。我尝试了您的解决方案,添加了nobrl,但仍然出现相同的错误。在本地运行正常。 - Sandro4912

13

我的电脑上打开了SQLite3 IDE,这才导致它显示“锁定”信息。我假设是在IDE中操作数据库而没有保存更改,因此会出现锁定。

简言之,检查数据库是否有未保存的更改,并确保它没有在其他地方被使用。


13

问题原因是数据库文件路径实际上是一个samba挂载的目录,移动后问题得到解决。


11

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

$ fuser development.db

这个命令会显示哪个进程锁定了该文件:

development.db: 5430

只需杀死该进程…

kill -9 5430

...然后您的数据库将被解锁。


5

这里有一个同时访问的巧妙解决方案:

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)
# ...

2
你忘记写 continue 了吗? - remram
15
让他休息一下。 - Eric
顺便提一下,timeout=1 是多余的:在大多数情况下,默认的5秒超时时间已经足够了。 - Eric

5

因为这仍然是此问题的谷歌搜索排名最高的结果,所以让我添加一个可能的原因。如果您正在编辑数据库结构并且尚未提交更改,则数据库将被锁定,直到您提交或还原更改。

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


4

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


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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接