我在我的应用程序中做了一些重复的操作(测试它),突然我得到一个奇怪的错误:
OperationalError: database is locked
我已经重新启动了服务器,但错误仍然存在。这到底是怎么回事?
来自 django 文档:
SQLite 旨在成为轻量级数据库,因此无法支持高级别的并发。OperationalError: database is locked 错误表明您的应用程序遇到的并发性超出了 sqlite 在默认配置中可以处理的数量。这个错误意味着一个线程或进程在数据库连接上有一个排他锁,而另一个线程超时等待锁被释放。
Python 的 SQLite 包装器有一个默认的超时值,它决定了第二个线程在超时之前允许在锁上等待多长时间并引发 OperationalError: database is locked 错误。
如果您收到此错误,您可以通过以下方式解决:
- 切换到另一个数据库后端。在某个时刻,SQLite 对于现实世界的应用程序来说变得太“精简”了,而这些并发错误表明您已经达到了这一点。
- 重写代码以减少并发并确保数据库事务是短暂的。
- 通过设置 timeout 数据库选项增加默认超时值
http://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errorsoption
就我而言,这是因为我从 SQLite 浏览器打开数据库。当我从浏览器关闭它时,问题就消失了。
造成这种情况的实际原因通常是 python 或 django shell 已经打开了对 DB 的请求,但没有正确关闭;杀死您的终端访问通常可以释放它。我今天在运行命令行测试时遇到了这个错误。
编辑:我对此定期进行投票。如果您想在不重新启动终端的情况下终止访问,那么您可以从命令行执行以下操作:
from django import db
db.connections.close_all()
我不同意@Patrick 的回答,通过引用此文档,将 OP 的问题 ( Database is locked
) 隐式链接到此:
切换到另一个数据库后端。在某个时刻,SQLite 对于现实世界的应用程序来说变得太“精简”了,而这些并发错误表明您已经达到了这一点。
这有点“太容易”将 SQlite 归咎于这个问题(正确使用时非常强大;它不仅是小型数据库的玩具,有趣的事实:)An SQLite database is limited in size to 140 terabytes
。
除非您有一个非常繁忙的服务器,同时有数千个连接,否则此错误的原因Database is locked
可能更多是对 API 的错误使用,而不是 SQlite 固有的“太轻”的问题。以下是有关SQLite 实施限制的更多信息。
现在解决方案:
当我同时使用同一个数据库的两个脚本时,我遇到了同样的问题:
解决方案:总是cursor.close()
在完成(甚至是只读的)查询后尽快执行。
正如其他人所说,还有另一个进程正在使用 SQLite 文件并且没有关闭连接。如果您使用的是 Linux,您可以使用以下命令查看哪些进程正在使用该文件(例如db.sqlite3
)fuser
:
$ sudo fuser -v db.sqlite3
USER PID ACCESS COMMAND
/path/to/db.sqlite3:
user 955 F.... apache2
如果要停止进程以释放锁,请使用fuser -k
which 将KILL
信号发送到访问文件的所有进程:
sudo fuser -k db.sqlite3
请注意,这是危险的,因为它可能会停止生产服务器中的 Web 服务器进程。
感谢@cz-game 指出fuser
!
在 patrick 的答案中链接的帮助信息未(明确)解决的情况下,我遇到了此错误消息。
当我过去从两个不同的线程同时transaction.atomic()
包装FooModel.objects.get_or_create()
并调用该代码时,只有一个线程会成功,而另一个线程会收到“数据库已锁定”错误。更改超时数据库选项对行为没有影响。
我认为这是因为 sqlite无法同时处理多个写入者,因此应用程序必须自己序列化写入。
我通过使用threading.RLock
对象而不是transaction.atomic()
当我的 Django 应用程序使用 sqlite 后端运行时解决了这个问题。这并不完全等效,因此您可能需要在应用程序中执行其他操作。
这是我的代码,它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())
使用保存在 WSL (\\wsl$ ...) 下的数据库文件并运行 Windows python 解释器时出现此错误。
您可以不将数据库保存在 WSL 树中,也可以在发行版中使用基于 linux 的解释器。
如果您通过 pycharm 通过 dbbrowser 插件连接到您的 sqlite 数据库,也会发生这种情况。断线就能解决问题
对我来说,一旦我关闭使用打开的 django shell,它就会得到解决python manage.py shell
我有同样的错误!原因之一是数据库连接未关闭。因此,检查未关闭的数据库连接。另外,在关闭连接之前检查您是否已提交数据库。
在第一次实例化 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
只需关闭(停止)并打开(启动)数据库。这解决了我的问题。
我发现这可以满足我的需要。(线程锁定) YMMV conn = sqlite3.connect(database, timeout=10)
https://docs.python.org/3/library/sqlite3.html
sqlite3.connect(数据库[,超时,detect_types,isolation_level,check_same_thread,工厂,cached_statements,uri])
当一个数据库被多个连接访问,并且其中一个进程修改了数据库时,SQLite 数据库将被锁定,直到该事务被提交。timeout 参数指定连接应该等待锁消失多长时间,直到引发异常。超时参数的默认值为 5.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)>]>
检查您的数据库是否在另一个数据库浏览器上打开。
如果它在其他应用程序上打开,则关闭该应用程序并再次运行该程序。
就我而言,我没有保存在 SQLite 浏览器中执行的数据库操作。保存它解决了这个问题。
一个非常不寻常的场景,发生在我身上。
有无限递归,不断创建对象。
更具体地说,使用 DRF,我在视图中覆盖了 create 方法,我做到了
def create(self, request, *args, **kwargs):
....
....
return self.create(request, *args, **kwargs)
这里已经有很多答案了,即使我想分享我的案例,这可能会对某人有所帮助..
我已经在 Python API 中打开了连接以更新值,只有在收到服务器响应后我才会关闭连接。在这里,我所做的是在关闭 Python API 中的连接之前,我已经打开了连接以在服务器中执行一些其他操作。
如果您在使用时遇到此错误manage.py shell
,一个可能的原因是您有一个正在运行的开发服务器 ( manage.py runserver
),它正在锁定数据库。在使用 shell 时停止服务器总是为我解决了这个问题。
实际上我遇到了同样的问题,当我使用“transaction.atomic() 和 select_for_update()”时,我收到错误消息“OperationalError:数据库已锁定”,
经过多次尝试/搜索/阅读 django 文档,我发现 SQLite 本身的问题它不支持 django 文档所说的 select_for_update 方法,请查看以下 url 并深入阅读:
https://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errors
,当我搬到 MySQL 时,一切都很好。
正如 django DOCs 还说当数据库超时发生时可能会发生“数据库被锁定”,他们建议您通过设置以下选项来更改数据库超时:
'OPTIONS': {
# ...
'timeout': 20,
# ...
}
最后,我推荐你使用 MySQL/PostgreSQL,即使你是在开发环境中工作。
我希望这对你有帮助。
尝试在 SQLite 中创建新表时出现此错误,但session
对象包含未提交(尽管已刷新)的更改。
确保:
@Shilp Thapak的回答是正确的:错误的原因是在运行应用程序之前,您没有在 SQLite 数据库浏览器中手动更改数据。
如果您没有在您使用的任何 SQL 客户端中编写更改,您仍然可以创建引擎,但是
engine.connect()
将抛出有关数据库被锁定的操作错误。
您可以通过检查回滚日志的存在来检查您的引擎是否可以连接。回滚日志的默认模式是在事务开始和结束时创建和删除。
它存在于您的数据库所在的同一目录中,它与数据库文件具有相同的名称并附加了后缀“-journal”。
如果模式未更改,则在 DB Browser for SQLite 的 Edit pragmas 面板中的 Journal mode 中。
您可以像这样检查临时文件的存在:
if os.path.isfile('your-database.sqlite-journal'):
print("The database is locked. Please write your changes in your SQL client before proceeding.\n")
在此处阅读有关临时文件的更多信息。
因此,无需为此关闭 SQLite 的服务器或数据库浏览器。事实上,只要写入所有更改,您就可以让多个客户端同时连接到数据库,并且仍然同时运行您的应用程序。
更新django 版本 2.1.7
我sqlite3.OperationalError: database is locked
使用pytest
with得到了这个错误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 ... == ....
只需重新启动服务器,它将清除所有当前锁定数据库的进程。
试试这个命令:
sudo fuser -k 8000/tcp