我在我的应用程序中进行了一些重复操作(测试它),突然间我遇到了一个奇怪的错误:
OperationalError: database is locked
我重新启动了服务器,但错误仍然存在。它有什么关系?
答案 0 :(得分:56)
来自django doc:
SQLite意味着轻量级 数据库,因此不能支持 高并发性。 OperationalError:数据库已锁定 错误表明您的申请 正在经历更多的并发性 sqlite可以默认处理 组态。这个错误意味着 一个线程或进程具有独占权 锁定数据库连接和 另一个线程超时等待 锁被释放。
Python的SQLite包装器有一个默认值 超时值,确定多长时间 允许第二个线程等待 在锁定超时之前锁定 引发OperationalError:数据库 是锁定错误。
如果您收到此错误,则可以 通过以下方式解决:
切换到另一个数据库后端。 在某个时刻,SQLite也变得如此 “lite”用于实际应用, 和这些类型的并发错误 表明你已达到这一点。
重写代码以减少 并发并确保数据库 交易是短暂的。
增加默认超时值 设置超时数据库选项 optionoption
http://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errorsoption
答案 1 :(得分:23)
实际的原因通常是python或django shell已经向DB打开了一个请求并且没有正确关闭;杀死你的终端访问通常会释放它。我今天在运行命令行测试时遇到此错误。
编辑:我定期对此进行投票。如果您想在不重新启动终端的情况下终止访问权限,那么可以从命令行执行以下操作:
from django import db
db.connections.close_all()
答案 2 :(得分:13)
在我的情况下,这是因为我从SQLite浏览器打开数据库。当我从浏览器关闭它时,问题就消失了。
答案 3 :(得分:4)
我不同意@Patrick的回答,该回答通过引用此文档,将OP的问题(Database is locked
)隐式链接到此:
切换到另一个数据库后端。在某些时候,SQLite对于实际的应用程序来说太“精简”了,这些并发错误表明您已经达到了这一点。
将这个问题归咎于SQlite有点“太容易了”。除非您有一个非常繁忙的服务器同时具有成千上万的连接,否则此Database is locked
错误的原因可能是API的错误使用,而不是SQlite固有的问题“轻”。。这是有关Implementation Limits for SQLite的更多信息。
现在解决方案:
当我同时使用两个脚本使用同一数据库时,我遇到了相同的问题:
解决方案:在进行了(甚至是只读的)查询后,总是尽快执行cursor.close()
。
答案 4 :(得分:3)
在帕特里克答案中所链接的帮助信息无法(显然)解决的情况下,我遇到了此错误消息。
当我使用transaction.atomic()
包装对FooModel.objects.get_or_create()
的调用并从两个不同的线程同时调用该代码时,只有一个线程会成功,而另一个线程会收到“数据库已锁定”错误。更改超时数据库选项对此行为没有影响。
我认为这是由于sqlite cannot handle multiple simultaneous writers,因此应用程序必须自行序列化写入。
当我的Django应用通过sqlite后端运行时,我通过使用threading.RLock
对象而不是transaction.atomic()
解决了这个问题。这并不完全等效,因此您可能需要在应用程序中做其他事情。
这是我的代码,可以从两个不同的线程同时运行FooModel.objects.get_or_create
,以防万一:
from concurrent.futures import ThreadPoolExecutor
import configurations
configurations.setup()
from django.db import transaction
from submissions.models import ExerciseCollectionSubmission
def makeSubmission(user_id):
try:
with transaction.atomic():
e, _ = ExerciseCollectionSubmission.objects.get_or_create(
student_id=user_id, exercise_collection_id=172)
except Exception as e:
return f'failed: {e}'
e.delete()
return 'success'
futures = []
with ThreadPoolExecutor(max_workers=2) as executor:
futures.append(executor.submit(makeSubmission, 296))
futures.append(executor.submit(makeSubmission, 297))
for future in futures:
print(future.result())
答案 5 :(得分:2)
我有同样的错误!原因之一是数据库连接未关闭。 因此,请检查未关闭的数据库连接。另外,在关闭连接之前,请检查是否已提交数据库。
答案 6 :(得分:2)
在Django(v3.0.3)的第一个实例化之后,我也遇到了类似的错误。除了以下内容,这里的所有建议均无效:
db.sqlite3
文件,并丢失了其中的数据python manage.py makemigrations
python manage.py migrate
顺便说一句,如果您只想测试PostgreSQL:
docker run --rm --name django-postgres \
-e POSTGRES_PASSWORD=mypassword \
-e PGPORT=5432 \
-e POSTGRES_DB=myproject \
-p 5432:5432 \
postgres:9.6.17-alpine
更改settings.py
以添加此DATABASES
:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'myproject',
'USER': 'postgres',
'PASSWORD': 'mypassword',
'HOST': 'localhost',
'PORT': '5432',
}
}
...并添加数据库适配器:
pip install psycopg2-binary
那么通常:
python manage.py makemigrations
python manage.py migrate
答案 7 :(得分:1)
如果通过pycharm通过dbbrowser插件连接到sqlite db,也可能发生这种情况。断开连接将解决问题
答案 8 :(得分:1)
对我来说,一旦我关闭了使用python manage.py shell
打开的django shell,它就会解决。
答案 9 :(得分:1)
我在使用保存在 WSL (\\wsl$ ...) 下的数据库文件并运行 windows python 解释器时遇到此错误。
您既不能将数据库保存在 WSL 树中,也不能在发行版中使用基于 linux 的解释器。
答案 10 :(得分:1)
我发现这可以满足我的需求。 (线程锁定)YMMV conn = sqlite3.connect(数据库,超时= 10)
https://docs.python.org/3/library/sqlite3.html
sqlite3.connect(数据库[,超时,detect_types,isolation_level,check_same_thread,factory,cached_statements,uri])
当通过多个连接访问数据库,并且其中一个进程修改了数据库时,SQLite数据库将被锁定,直到提交该事务为止。 timeout参数指定连接应等待多长时间才能引发锁,直到引发异常为止。超时参数的默认值为5.0(五秒)。
答案 11 :(得分:0)
检查您的数据库是否在另一个数据库浏览器上打开。
如果它是在其他应用程序上打开的,则关闭该应用程序并再次运行该程序。
答案 12 :(得分:0)
就我而言,我没有保存在SQLite浏览器中执行的数据库操作。保存它可以解决问题。
答案 13 :(得分:0)
尝试在 SQLite 中创建新表时出现此错误,但 session
对象包含未提交(尽管已刷新)的更改。
确保:
答案 14 :(得分:0)
实际上我遇到了同样的问题,当我使用“transaction.atomic() 和 select_for_update()”时,我收到错误消息“OperationalError:数据库被锁定”,
经过多次尝试/搜索/阅读 django 文档, 我从 SQLite 本身发现问题,它不支持 select_for_update 方法,如 django DOC 所说,请查看以下网址并深入阅读:
https://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errors
,当我迁移到 MySQL 时一切正常。
因为 django DOCs 还说当数据库超时发生时可能会发生“数据库被锁定”, 他们建议您通过设置以下选项来更改数据库超时:
'OPTIONS': {
# ...
'timeout': 20,
# ...
}
最后,即使你在开发环境中工作,我还是建议你使用 MySQL/PostgreSQL。
希望对你有帮助。
答案 15 :(得分:0)
对于我来说,我添加了一个手动保存的新记录,然后再次通过shell尝试添加新记录,这次它可以很好地将其检出。
In [7]: from main.models import Flight
In [8]: f = Flight(origin="Florida", destination="Alaska", duration=10)
In [9]: f.save()
In [10]: Flight.objects.all()
Out[10]: <QuerySet [<Flight: Flight object (1)>, <Flight: Flight object (2)>, <Flight: Flight object (3)>, <Flight: Flight object (4)>]>
答案 16 :(得分:0)
如果在使用manage.py shell
时遇到此错误,则可能的原因是您正在运行的开发服务器(manage.py runserver
)锁定了数据库。使用Shell时停止服务器始终可以解决我的问题。
答案 17 :(得分:0)
这里已经有很多答案,即使我想分享我的情况,这也可能对某人有所帮助。
我已经在Python API中打开了连接以更新值,只有在收到服务器响应后我才会关闭连接。在这里,我所做的是在关闭Python API中的连接之前,我还打开了连接以在服务器中执行其他操作。
答案 18 :(得分:0)
一个非常不寻常的情况发生在我身上。
存在无限递归,因此不断创建对象。
更具体地说,使用DRF,我在视图中覆盖了create方法,而我做到了
def create(self, request, *args, **kwargs):
....
....
return self.create(request, *args, **kwargs)
答案 19 :(得分:0)
正如其他人所说,还有另一个进程正在使用SQLite文件,但尚未关闭连接。如果您使用的是Linux,则可以使用db.sqlite3
命令来查看哪些进程正在使用该文件(例如fuser
),如下所示:
$ sudo fuser -v db.sqlite3
USER PID ACCESS COMMAND
/path/to/db.sqlite3:
user 955 F.... apache2
如果要停止释放锁的进程,请使用fuser -k
,它向所有访问文件的进程发送KILL
信号:
sudo fuser -k db.sqlite3
请注意,这样做很危险,因为它可能会停止生产服务器中的Web服务器进程。
感谢@ cz-game指出fuser
!
答案 20 :(得分:0)
更新 django版本2.1.7
我将sqlite3.OperationalError: database is locked
与pytest
一起使用时出现了此错误django
。
解决方案:
如果我们使用@pytest.mark.django_db
装饰器。它的作用是创建一个in-memory-db
进行测试。
名称:file:memorydb_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 ... == ....
答案 21 :(得分:-1)
只需重新启动服务器,它就会清除所有已锁定数据库的当前进程。
答案 22 :(得分:-7)
尝试此命令:
sudo fuser -k 8000/tcp