Python 操作错误:数据库已锁定

Python 操作错误:数据库已锁定,python,django,database,sqlite,locked,Python,Django,Database,Sqlite,Locked,我在我的应用程序中进行了一些重复操作(测试),突然出现了一个奇怪的错误: OperationalError: database is locked 我已重新启动服务器,但错误仍然存在。这是怎么回事?来自django doc: SQLite是轻量级的 数据库,因此无法支持 高水平的并发性。 操作错误:数据库已锁定 错误表明您的应用程序 正在经历比以前更多的并发性 sqlite在默认情况下可以处理 配置这个错误意味着 一个线程或进程具有独占 锁定数据库连接并 另一个线程在等待时超时 锁不能松开 P

我在我的应用程序中进行了一些重复操作(测试),突然出现了一个奇怪的错误:

OperationalError: database is locked
我已重新启动服务器,但错误仍然存在。这是怎么回事?

来自django doc:

SQLite是轻量级的 数据库,因此无法支持 高水平的并发性。 操作错误:数据库已锁定 错误表明您的应用程序 正在经历比以前更多的并发性 sqlite在默认情况下可以处理 配置这个错误意味着 一个线程或进程具有独占 锁定数据库连接并 另一个线程在等待时超时 锁不能松开

Python的SQLite包装器有一个默认值 超时值,用于确定超时时间 允许第二个线程等待 在锁超时和关闭之前打开它 引发错误:数据库 是锁定错误

如果您遇到此错误,您可以 通过以下方式解决此问题:

  • 切换到另一个数据库后端。在某一点上,SQLite对于现实世界的应用程序来说变得过于“精简”,而这些并发错误表明您已经达到了这一点
  • 重写代码以降低并发性并确保数据库事务是短期的
  • 通过设置超时数据库选项增加默认超时值

这种情况的实际原因通常是python或django shell打开了对DB的请求,但没有正确关闭;终止终端访问通常会释放它。我今天在运行命令行测试时出现了这个错误

编辑:我得到定期的投票。如果希望在不重新启动终端的情况下终止访问,则可以从命令行执行以下操作:

from django import db
db.connections.close_all()

在我的例子中,这是因为我从SQLite浏览器打开了数据库。当我从浏览器关闭它时,问题就消失了。

请尝试以下命令:

sudo fuser -k 8000/tcp

在我的例子中,我没有保存在SQLite浏览器中执行的数据库操作。保存它解决了问题。

我不同意@Patrick的回答,他引用了这篇文档,暗示OP的问题(
数据库被锁定
)与此相关:

切换到另一个数据库后端。在某一点上,SQLite对于现实世界的应用程序来说变得过于“精简”,而这些并发错误表明您已经达到了这一点

这有点“太容易”将SQlite归咎于这个问题(如果正确使用,它不仅是小型数据库的玩具,有趣的事实是:
SQlite数据库的大小限制为140 TB

除非您的服务器非常繁忙,同时有数千个连接,
数据库被锁定的原因可能更多地是API使用不当,而不是SQlite固有的问题,即“太轻”。这里有更多的信息


现在,解决方案是:

当我同时使用同一数据库的两个脚本时,我遇到了同样的问题:

  • 一个是通过写操作访问数据库
  • 另一个正在以只读方式访问数据库
解决方案:总是在完成(甚至是只读)查询后尽快执行
cursor.close()


.

如果您通过pycharm通过dbbrowser插件连接到sqlite db,也可能发生这种情况。断开连接将解决问题

对我来说,一旦我关闭了django shell,它就会得到解决,django shell是使用
python manage.py shell打开的
更新django版本2.1.7

我得到了这个错误
sqlite3.OperationalError:数据库被锁定
使用
pytest
django

解决方案:

如果我们使用的是
@pytest.mark.django_db
装饰器。它所做的是在内存db中创建一个用于测试的

命名:
file:memorydb\u default?mode=memory&cache=shared
我们可以通过以下方式获得此名称:

from django.db import connection
db_path = connection.settings_dict['NAME']
要访问并编辑此数据库,请执行以下操作:

连接到数据库:

with sqlite3.connect(db_path, uri=True) as conn:
    c = conn.cursor()
使用
uri=True
指定作为要打开的SQLite数据库的磁盘文件

要避免此错误,请在装饰器中激活事务:

@pytest.mark.django_db(transaction=True)
最终功能:

from django.db import connection

@pytest.mark.django_db(transaction=True)
def test_mytest():
    db_path = connection.settings_dict['NAME']
    with sqlite3.connect(db_path, uri=True) as conn:
        c = conn.cursor()
        c.execute('my amazing query')
        conn.commit()
    assert ... == ....

正如其他人所说,还有另一个进程正在使用SQLite文件,但尚未关闭连接。如果您使用的是Linux,则可以使用
fuser
命令查看哪些进程正在使用该文件(例如
db.sqlite3
),如下所示:

$sudo fuser-v db.sqlite3
用户PID访问命令
/路径/to/db.sqlite3:
用户955F。。。。apache2
如果要停止进程以释放锁,请使用
fuser-k
,它会向访问文件的所有进程发送
KILL
信号:

sudo fuser-k db.sqlite3
请注意,这是危险的,因为它可能会停止生产服务器中的web服务器进程


感谢@cz game指出fuser

我也犯了同样的错误!原因之一是数据库连接未关闭。
因此,请检查是否有未关闭的数据库连接。另外,在关闭连接之前,请检查您是否提交了数据库。

我在patrick回答中链接的帮助信息没有(清楚)说明的情况下遇到了此错误消息

当我使用
transaction.atomic()
包装对
FooModel.objects.get\u或\u create()
的调用,并从两个不同的线程同时调用该代码时,只有一个线程会成功,而另一个线程会出现“database is locked”错误。更改超时数据库选项对行为没有影响

我认为这是由于sqlite的存在,因此应用程序必须自己序列化写操作

我用
th解决了这个问题
pip install psycopg2-binary
python manage.py makemigrations
python manage.py migrate
def create(self, request, *args, **kwargs):
    ....
    ....

    return self.create(request, *args, **kwargs)
'OPTIONS': {
    # ...
    'timeout': 20,
    # ...
}