操作错误:数据库被锁定
- 2025-03-18 08:56:00
- admin 原创
- 58
问题描述:
我在我的应用程序中进行了一些重复操作(测试它),突然出现了一个奇怪的错误:
OperationalError: database is locked
我重启了服务器,但错误仍然存在。这是什么原因?
解决方案 1:
来自Django的文档:
SQLite 旨在成为轻量级数据库,因此无法支持高并发水平。
OperationalError: database is locked
错误表明您的应用程序遇到的并发量超出了sqlite
默认配置的处理能力。此错误意味着一个线程或进程对数据库连接拥有独占锁,而另一个线程在等待释放锁时超时。Python 的 SQLite 包装器有一个默认超时值,该值决定了第二个线程在超时并引发错误之前可以在锁上等待多长时间
OperationalError: database is locked
。如果您收到此错误,可以通过以下方式解决:
切换到另一个数据库后端。在某个时候,SQLite 对于实际应用程序来说变得太“精简”,这些并发错误表明您已经到达了那个点。
重写代码以减少并发性并确保数据库事务是短暂的。
通过设置数据库选项来增加默认超时值
timeout
:"OPTIONS": { # ... "timeout": 20, # ... }
这将使 SQLite 等待更长时间才抛出“数据库已锁定”错误;它实际上不会采取任何措施来解决这些问题。
解决方案 2:
我稍微不同意接受的答案,该答案通过引用该文档,隐式地将 OP 的问题 ( Database is locked
) 与此联系起来:
切换到另一个数据库后端。在某个时候,SQLite 对于实际应用程序来说变得太“精简”,这些并发错误表明您已经到达了那个点。
将此问题归咎于 SQlite 有点“太容易了”(如果正确使用,它非常强大;它不仅是小型数据库的玩具,有趣的事实An SQLite database is limited in size to 140 terabytes
:)。
除非您的服务器非常繁忙,同时有数千个连接,否则此错误的原因Database is locked
可能更多是 API 的错误使用,而不是 SQlite 固有的“太轻”问题。以下是有关SQLite 实现限制的更多信息。
现在解决方案:
当我同时使用两个使用同一个数据库的脚本时遇到了同样的问题:
一个是使用写操作访问数据库
另一个是以只读方式访问数据库
解决方案:在完成(即使是只读)查询后始终尽快执行。cursor.close()
以下是更多详细信息。
解决方案 3:
就我而言,这是因为我从SQLite 的数据库浏览器打开了数据库。当我从浏览器关闭它时,问题就消失了。
解决方案 4:
造成这种情况的实际原因通常是 python 或 django shell 已打开对数据库的请求,但未正确关闭;终止终端访问通常可以释放它。我今天在运行命令行测试时遇到了这个错误。
编辑:我定期收到对此的点赞。如果您想在不重新启动终端的情况下终止访问,那么您可以从命令行执行以下操作:
from django import db
db.connections.close_all()
解决方案 5:
我遇到了这个错误信息,但 Patrick 的答案中链接的帮助信息没有(明确)解决这个问题。
当我包装transaction.atomic()
调用FooModel.objects.get_or_create()
并从两个不同的线程同时调用该代码时,只有一个线程会成功,而另一个线程会收到“数据库已锁定”错误。更改超时数据库选项对行为没有影响。
我认为这是因为 sqlite无法处理多个同时的写入操作,所以应用程序必须自行序列化写入。
当我的 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())
解决方案 6:
正如其他人所说,还有另一个进程正在使用 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
!
解决方案 7:
当我使用在 WSL(\\wsl$...)下保存的数据库文件并运行 Windows Python 解释器时出现此错误。
您既可以不在 WSL 树中保存数据库,也可以在发行版中使用基于 Linux 的解释器。
解决方案 8:
我在我的 flask 应用程序中遇到了这个问题,因为我在 SQLite 浏览器中打开了数据库但忘记写入更改。
如果您也在 SQLite 浏览器中做了任何更改,请单击写入更改,一切都会正常。
解决方案 9:
对我来说,一旦我关闭使用以下方式打开的 django shell,这个问题就会得到解决python manage.py shell
解决方案 10:
如果您通过 pycharm 的 dbbrowser 插件连接到 sqlite db,也可能会发生这种情况。断开连接将解决问题
解决方案 11:
我遇到了同样的错误!原因之一是数据库连接未关闭。因此,请检查未关闭的数据库连接。此外,在关闭连接之前,请检查是否已提交数据库。
解决方案 12:
在第一次实例化 Django (v3.0.3) 之后,我遇到了类似的错误。除了以下情况外,这里的所有建议都不起作用:
删除了
db.sqlite3
文件并丢失了其中的数据(如果有的话),python manage.py makemigrations
python manage.py migrate
顺便说一句,如果您只想测试 PostgreSQL:
docker run --rm --name django-postgres \n -e POSTGRES_PASSWORD=mypassword \n -e PGPORT=5432 \n -e POSTGRES_DB=myproject \n -p 5432:5432 \n 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
解决方案 13:
检查您的数据库是否在另一个数据库浏览器上打开。
如果它在其他应用程序上打开,则关闭该应用程序并再次运行该程序。
解决方案 14:
只需关闭(停止)并打开(启动)数据库即可。这解决了我的问题。
解决方案 15:
我发现这可以满足我的需要。(线程锁定)YMMV conn = sqlite3.connect(数据库,超时=10)
https://docs.python.org/3/library/sqlite3.html
sqlite3.connect(数据库[,超时,检测类型,隔离级别,检查相同线程,工厂,缓存语句,uri])
当多个连接访问数据库时,如果其中一个进程修改了数据库,则 SQLite 数据库将被锁定,直到提交该事务。超时参数指定连接应等待锁定消失的时间,直到引发异常。超时参数的默认值为 5.0(五秒)。
解决方案 16:
就我而言,我添加了一条手动保存的新记录,并再次通过 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)>]>
解决方案 17:
实际上我也遇到过同样的问题,当我使用“transaction.atomic() with select_for_update()”时,我收到错误消息“OperationalError:数据库已锁定”,
经过多次尝试/搜索/阅读 django 文档后,我发现问题出在 SQLite 本身,它不支持 select_for_update 方法,正如 django DOCs 所说,请查看以下网址并深入阅读:
https://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errors
,当我转到 MySQL 时,一切都顺利。
由于 django DOCs 也说当数据库超时时可能会发生“数据库被锁定”,他们建议您通过设置以下选项来更改数据库超时:
'OPTIONS': {
# ...
'timeout': 20,
# ...
}
最后,即使您在开发环境中工作,我建议您使用 MySQL/PostgreSQL。
我希望这对你有帮助。
解决方案 18:
就我的情况而言,我没有保存在 SQLite 浏览器中执行的数据库操作。保存后问题就解决了。
解决方案 19:
这是一个非常不寻常的情况,它发生在我身上。
存在无限递归,不断创建对象。
更具体地说,使用 DRF,我在视图中覆盖了创建方法,并且我做到了
def create(self, request, *args, **kwargs):
....
....
return self.create(request, *args, **kwargs)
解决方案 20:
这里已经有很多答案,我甚至想分享我的案例,这可能会对某些人有所帮助。
我已经在 Python API 中打开了连接来更新值,只有在收到服务器响应后才会关闭连接。这里我所做的是,在关闭 Python API 中的连接之前,我已经打开了连接以在服务器中执行其他操作。
解决方案 21:
如果您在使用时收到此错误manage.py shell
,则可能的原因之一是您正在运行的开发服务器 ( manage.py runserver
) 正在锁定数据库。使用 shell 时停止服务器总能解决问题。
解决方案 22:
当我尝试在 SQLite 中创建一个新表但session
对象包含未提交的(虽然已刷新)更改时出现此错误。
请确保:
在创建新表之前提交会话
关闭所有会话并在新连接中执行表创建
...
解决方案 23:
@Shilp Thapak的回答是正确的:错误的原因是您在运行应用程序之前没有将手动更改写入 SQLite 数据库浏览器中的数据。
如果你没有在你使用的 SQL 客户端中写入更改,你仍然可以创建引擎,但是
engine.connect()
运行代码片段Hide results展开片段
将抛出有关数据库被锁定的操作错误。
您可以通过检查回滚日志是否存在来检查您的引擎是否可以连接。回滚日志的默认模式是在事务开始和结束时创建和删除。
它存在于数据库所在的同一目录中,与数据库文件具有相同的名称并附加后缀“-journal”。
如果模式没有改变,则在 SQLite 的 DB 浏览器中的编辑编译指示面板中的日志模式下。
您可以像这样检查临时文件是否存在:
if os.path.isfile('your-database.sqlite-journal'):
print("The database is locked. Please write your changes in your SQL client before proceeding.
")
运行代码片段Hide results展开片段
在这里阅读有关临时文件的更多信息。
因此无需为此关闭 SQLite 的服务器或数据库浏览器。事实上,只要写入所有更改,您就可以让多个客户端同时连接到数据库,并且仍可同时运行您的应用程序。
解决方案 24:
对于我来说,我尝试使用 gunicorn 将数据库部署到主机,并且我只使用了一个工作程序,因此数据库被锁定。添加到 gunicorn_config.py
工人=3
解决方案 25:
我在服务生产 DJANGO 服务器上遇到了同样的问题。我们通过使用 DB 工具(例如“DB Browser”)缩小 sqlite DB 来解决问题。
解决方案 26:
我的解决方案是,我忘记在执行查询后使用 conn.commit()。
解决方案 27:
当我从 Excel 文件向表中插入值时,出现了错误。我执行此操作时打开了我的 Excel 文件。关闭 Excel 文件后,一切正常。所以也许可以检查是否有其他程序访问过您的文件。我想这可以帮助处于类似情况的其他人。
解决方案 28:
我刚刚解决了很难找到支持 WAL(预写日志)的记录标志的问题。
这是其他数据库中相当标准和默认的,并且提供了更好的并发性,请readers do not block writers and a writer does not block readers. Reading and writing can proceed concurrently.
参阅https://www.sqlite.org/wal.html
因此只需确保通过执行以下操作来更改 journal_mode:
PRAGMA journal_mode=WAL
解决方案 29:
更新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 ... == ....
解决方案 30:
我只需要添加alias sqlite='sqlite3'
到我的~/.zshrc
然后我删除了部分失败的创建并重新运行virtualenv
,它运行得很顺利~/.pyenv/versions/new-virtualenv
`pyenv virtualenv <name>`
扫码咨询,免费领取项目管理大礼包!