【发布时间】:2024-04-29 20:35:01
【问题描述】:
我在我的应用程序中做了一些重复的操作(测试它),突然我得到一个奇怪的错误:
OperationalError: database is locked
我已重新启动服务器,但错误仍然存在。这到底是怎么回事?
【问题讨论】:
标签: python django database sqlite locked
我在我的应用程序中做了一些重复的操作(测试它),突然我得到一个奇怪的错误:
OperationalError: database is locked
我已重新启动服务器,但错误仍然存在。这到底是怎么回事?
【问题讨论】:
标签: python django database sqlite locked
@Shilp Thapak 的回答是正确的:错误的原因是您没有在运行应用程序之前将手动更改写入 DB Browser for SQLite 中的数据。
如果您没有在所使用的任何 SQL 客户端中编写更改,您仍然可以创建引擎,但是
engine.connect()
将抛出有关数据库被锁定的操作错误。
您可以通过检查回滚日志的存在来检查您的引擎是否可以连接。回滚日志的默认模式是在事务开始和结束时创建和删除。
它与你的数据库在同一个目录下,它与数据库文件同名并附加后缀“-journal”。
如果模式没有改变,在Journal mode in Edit pragmas panel in DB Browser for SQLite。
您可以像这样检查临时文件的存在:
if os.path.isfile('your-database.sqlite-journal'):
print("The database is locked. Please write your changes in your SQL client before proceeding.\n")
阅读更多关于临时文件here。
因此,无需为此关闭 SQLite 的服务器或数据库浏览器。事实上,只要将所有更改都写入,您可以让多个客户端同时连接到数据库,并且仍然可以同时运行您的应用程序。
【讨论】:
检查您的数据库是否在另一个数据库浏览器上打开。
如果在其他应用程序上打开,则关闭该应用程序并再次运行该程序。
【讨论】:
我在使用保存在 WSL (\\wsl$ ...) 下的数据库文件并运行 windows python 解释器时收到此错误。
您可以不将数据库保存在 WSL 树中,也可以在发行版中使用基于 linux 的解释器。
【讨论】:
尝试在 SQLite 中创建新表时出现此错误,但 session 对象包含未提交(尽管已刷新)的更改。
请确保:
【讨论】:
实际上我也遇到过同样的问题,当我使用“transaction.atomic() 和 select_for_update()”时,我收到错误消息“操作错误:数据库已锁定”,
经过多次尝试/搜索/阅读 django 文档, 我从 SQLite 本身发现了问题,它不支持 django DOCs 所说的 select_for_update 方法,请查看以下网址并深入阅读:
https://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errors
,当我搬到 MySQL 时,一切都很好。
正如 django DOCs 还说,当数据库超时发生时,“数据库被锁定”可能会发生, 他们建议您通过设置以下选项来更改数据库超时:
'OPTIONS': {
# ...
'timeout': 20,
# ...
}
最后,我推荐你使用 MySQL/PostgreSQL,即使你是在开发环境中工作。
我希望这对你有帮助。
【讨论】:
正如其他人所说,有另一个进程正在使用 SQLite 文件并且尚未关闭连接。如果您使用的是 Linux,您可以使用 fuser 命令查看哪些进程正在使用该文件(例如 db.sqlite3),如下所示:
$ 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!
【讨论】:
sudo fuser -k app.db 在我的情况下
在我的例子中,我添加了一条手动保存的新记录,然后再次通过 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)>]>
【讨论】:
我发现这可以满足我的需求。 (线程锁定)YMMV conn = sqlite3.connect(数据库,超时=10)
https://docs.python.org/3/library/sqlite3.html
sqlite3.connect(database[, timeout, detect_types,isolation_level, check_same_thread, factory, cached_statements, uri])
当一个数据库被多个连接访问,并且其中一个进程修改了数据库时,SQLite 数据库将被锁定,直到该事务被提交。 timeout 参数指定连接应该等待锁消失多长时间,直到引发异常。超时参数的默认值为 5.0(五秒)。
【讨论】:
只需重新启动您的服务器,它将清除所有当前锁定您的数据库的进程。
【讨论】:
如果您在使用manage.py shell 时遇到此错误,一个可能的原因是您有一个正在运行的开发服务器 (manage.py runserver) 正在锁定数据库。在使用 shell 时停止服务器总是为我解决了这个问题。
【讨论】:
这里已经有很多答案了,即使我想分享我的案例,这可能会对某人有所帮助..
我已经在 Python API 中打开了连接以更新值,只有在收到服务器响应后我才会关闭连接。我在这里所做的是在关闭 Python API 中的连接之前,我已经打开了连接以在服务器中执行一些其他操作。
【讨论】:
只需关闭(停止)并打开(启动)数据库。这解决了我的问题。
【讨论】:
一个非常不寻常的场景,发生在我身上。
无限递归,不断创建对象。
更具体地说,使用 DRF,我在视图中覆盖了 create 方法,我做到了
def create(self, request, *args, **kwargs):
....
....
return self.create(request, *args, **kwargs)
【讨论】:
在第一次实例化 Django (v3.0.3) 之后,我遇到了类似的错误。这里的所有建议都不起作用,除了:
db.sqlite3 文件并丢失了那里的数据(如果有的话)python manage.py makemigrationspython 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
【讨论】:
来自 django 文档:
SQLite 旨在成为一个轻量级的 数据库,因此不能支持 高并发。 OperationalError:数据库已锁定 错误表明您的应用程序 正在经历比 sqlite 默认可以处理 配置。这个错误意味着 一个线程或进程具有独占性 锁定数据库连接和 另一个线程超时等待 锁将被释放。
Python 的 SQLite 包装器有一个默认值 确定多长时间的超时值 允许第二个线程等待 在超时之前锁上 引发 OperationalError: database 被锁定错误。
如果您收到此错误,您可以 解决方法:
- 切换到另一个数据库后端。在某些时候,SQLite 对于实际应用程序来说变得过于“精简”,而这些并发错误表明您已经达到了这一点。
- 重写代码以减少并发并确保数据库事务是短暂的。
- 通过设置超时数据库选项来增加默认超时值
http://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errorsoption
【讨论】:
create_engine('sqlite:///{}'.format(xxx), connect_args={'timeout': 15})
我不同意@Patrick 的回答,该回答通过引用此文档将 OP 的问题 (Database is locked) 隐式链接到此:
切换到另一个数据库后端。在某个时刻,SQLite 对于现实世界的应用程序来说变得过于“精简”,而这些并发错误表明您已经达到了这一点。
将 SQlite 归咎于这个问题有点“太容易”(正确使用时为 very powerful;它不仅是小型数据库的玩具,有趣的事实:An SQLite database is limited in size to 140 terabytes)。
除非你有一个非常繁忙的服务器同时有数千个连接,这个Database is locked 错误的原因可能更多的是对 API 的错误使用,而不是 SQlite 固有的问题,即“太轻了”。这里有更多关于Implementation Limits for SQLite的信息。
现在解决办法:
当我同时使用同一个数据库的两个脚本时,我遇到了同样的问题:
解决方案:在完成(甚至是只读的)查询后,请尽快执行cursor.close()。
【讨论】:
我在 patrick 的答案中链接的帮助信息未(明确)解决的情况下遇到此错误消息。
当我使用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())
【讨论】:
我遇到了同样的错误!原因之一是数据库连接未关闭。 因此,请检查未关闭的数据库连接。此外,请在关闭连接之前检查您是否已提交数据库。
【讨论】:
更新 django 2.1.7 版
我在使用pytest 和django 时遇到此错误sqlite3.OperationalError: database is locked。
解决方案:
如果我们使用@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 ... == ....
【讨论】:
pytest,我不知道pytest.mark.django_db 做了什么。 sqlite docs 并不是说内存数据库有任何不同的并发约束。
对我来说,一旦我关闭使用 python manage.py shell 打开的 django shell,它就会得到解决
【讨论】:
如果您通过 pycharm 的 dbbrowser 插件连接到您的 sqlite 数据库,也会发生这种情况。断线就能解决问题
【讨论】:
就我而言,我没有保存在 SQLite 浏览器中执行的数据库操作。保存它解决了这个问题。
【讨论】:
试试这个命令:
sudo fuser -k 8000/tcp
【讨论】:
造成这种情况的实际原因通常是 python 或 django shell 已经打开了对 DB 的请求,但没有正确关闭;杀死您的终端访问通常可以释放它。我今天在运行命令行测试时遇到了这个错误。
编辑:我对此定期进行投票。如果您想在不重新启动终端的情况下终止访问,那么您可以从命令行执行:
from django import db
db.connections.close_all()
【讨论】:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<subfolder_with_setings.json>.settings") 否则,恕我直言,这里是最佳答案
db.connections.close_all() 提示。在我使用tearDown() 中的清理脚本之前,我一直在寻找可以解锁数据库的东西。这解决了它。谢谢。
from django.conf import settings settings.configure()。跨度>
就我而言,这是因为我从 SQLite 浏览器打开数据库。当我从浏览器关闭它时,问题就消失了。
【讨论】: