数据库被锁定

我在我的应用程序中做了一些重复的操作(测试它) ,突然我得到了一个奇怪的错误:

OperationalError: database is locked

我已经重新启动了服务器,但是错误仍然存在?

247677 次浏览

来自姜戈的文档:

SQLite 应该是轻量级的 数据库,因此不能支持 高级别并发性。 数据库被锁定 错误表示您的应用程序 正在经历比 Sqlite 在默认情况下可以处理 这个错误意味着 一个线程或进程具有独占 锁定数据库连接和 另一个线程超时等待 被解开的锁。

Python 的 SQLite 包装器有一个默认值 超时值,该值确定超时多长时间 允许第二个线程等待 在超时之前把锁打开 引发 OperationalError: database 是锁定错误。

如果你得到这个错误,你可以 用以下方法解决:

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

Http://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errorsoption

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

编辑: 我定期得到这方面的赞成票。如果您想在不重新启动终端的情况下终止访问,那么您可以从命令行执行以下操作:

from django import db
db.connections.close_all()

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

试试这个命令:

sudo fuser -k 8000/tcp

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

我有点不同意接受的答案,通过引用这个文档,隐含地链接 OP 的问题(Database is locked)到这个:

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

这有点“太容易”使 SQlite 成为这个问题的罪魁祸首(如果正确使用,它是 非常强大; 它不仅仅是小型数据库的玩具,有趣的事实是: An SQLite database is limited in size to 140 terabytes )。

除非您的服务器非常繁忙,并且在同一秒钟内有数千个连接,否则 这个 Database is locked错误的原因可能更多的是对 API 的错误使用,而不是 SQlite 固有的问题,因为后者“太轻”了。这里有更多关于 SQLite 的实现限制的信息。


现在的解决办法是:

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

  • 一种是通过写操作访问数据库
  • 另一个是以只读方式访问数据库

解决方案: 总是在完成一个(甚至只读)查询后尽快执行 cursor.close()

这里有更多的细节。

这也可能发生在您通过 pycharm 通过 db 浏览器插件连接到 sqlite db 的情况下。断开连接就能解决问题

对我来说,一旦我关闭使用 python manage.py shell打开的 django shell,它就会得到解决

更新 django version 2.1.7

我得到这个错误 sqlite3.OperationalError: database is locked使用 pytestdjango

解决方案:

如果我们使用的是 @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 ... == ....

正如其他人所说的,还有一个进程正在使用 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

我得到了相同的错误! 原因之一是数据库连接没有关闭。 因此,请检查 未关闭的数据库连接。另外,在关闭连接之前检查是否有 坚定不移数据库。

我遇到这个错误信息的情况下,没有(明确)解决的帮助信息链接在 Patrick 的答案。

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

我认为这是由于 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())

在第一次实例化 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

一个非常不寻常的情况,发生在我身上。

有无限的递归,继续创建对象。

更具体地说,使用 DRF,我在视图中重写 create 方法,我做到了

def create(self, request, *args, **kwargs):
....
....


return self.create(request, *args, **kwargs)

只需关闭(停止)和打开(启动)数据库。这解决了我的问题。

这里已经有很多答案,甚至我想分享我的案例,这可能会有所帮助。

我已经在 PythonAPI 中打开了连接以更新值,只有在接收到服务器响应后才会关闭连接。在这里,我所做的是在关闭 Python API 中的连接之前,打开连接以在服务器中执行其他操作。

如果在使用 manage.py shell时出现此错误,一个可能的原因是运行的开发服务器(manage.py runserver)正在锁定数据库。在使用 shell 时停止服务器总能为我解决这个问题。

只要重新启动服务器,它就会清除当前所有锁定数据库的进程。

我发现这个工作我的需要。(线程锁定) YMMV Con = sqlite3.connect (database,timeout = 10)

Https://docs.python.org/3/library/sqlite3.html

Connect (database [ ,timeout,Detect_ type,sis _ level,check _ same _ thread,Factory,cached _ statement,uri ])

当一个数据库被多个连接访问,并且其中一个进程修改了该数据库时,SQLite 数据库将被锁定,直到该事务被提交。Timeout 参数指定在引发异常之前连接应该等待锁消失多长时间。Timeout 参数的默认值是5.0(5秒)。

在我的例子中,我添加了一个手动保存的新记录,并再次通过 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)>]>

实际上我也遇到过同样的问题,当我使用“ transaction.atom ()和 select _ for _ update ()”时,我得到了错误消息“ the OperationalError: database is lock”,

在多次尝试/搜索/阅读 django 文档后, 我发现了 SQLite 本身的问题,它不支持 django DOC 所说的 select _ for _ update 方法,请查看下面的 URL 并深入阅读:

Https://docs.djangoproject.com/en/dev/ref/databases/#database-is-locked-errors

当我转移到 MySQL 的时候,一切都很顺利。

Django DOC 还说,当发生数据库超时时,可能会出现“数据库被锁定”的情况, 他们建议您通过设置以下选项来更改数据库超时:

'OPTIONS': {
# ...
'timeout': 20,
# ...
}

最后,我建议您使用 MySQL/PostgreSQL,即使您使用的是开发环境。

我希望这对你有帮助。

当我试图在 SQLite 中创建一个新表,但是 session对象包含未提交(虽然已刷新)的更改时,出现了这个错误。

两者都要做到:

  1. 在创建新表之前提交会话
  2. 关闭所有会话并在新连接中执行表创建
  3. ...

当使用 WSL (WSL $...)下保存的数据库文件并运行 windows python 解释器时,我得到了这个错误。

您可以不将数据库保存在 WSL 树中,也可以在发行版中使用基于 linux 的解释器。

检查您的数据库是否在另一个 DB 浏览器上打开。

如果它在其他应用程序上打开,则关闭该应用程序并再次运行该程序。

我在烧瓶应用程序中遇到了这个问题,因为我在 SQLiteBrowser 中打开了数据库,忘记了写更改。

如果您还在 SQLiteBrowser 中进行了任何更改,则 点击写更改,一切都会好起来的

enter image description here

@ ShipThapak 的回答是正确的: 出错的原因是在运行应用程序之前,您没有在 SQLite 的 DB Browser 中编写对数据的手动更改。

如果没有在正在使用的 SQL 客户机中编写更改,仍然可以创建引擎,但是

engine.connect()

will throw the operational error about the database being locked.

You can check whether your engine can connect by checking the existence of a rollback journal. The default mode of a rollback journal is to be created and deleted at the start and end of a transaction.

It is exists in the same directory where your database is, it has the same name as the database file and the suffix "-journal" appended.

If the mode is not changed, at Journal mode in Edit pragmas panel in DB Browser for SQLite.

You can check the existence of the temp file like so:

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 的服务器或 DB 浏览器。实际上,只要写入了所有更改,就可以让多个客户机同时连接到数据库,并且仍然可以同时运行应用程序。

对我来说,这仅仅是因为我在运行 Python 代码创建新表的同时访问了 SQLite 应用程序中的数据库。 在代码完成之前关闭 SQLite 解决了我的问题。

我只需要把 alias sqlite='sqlite3'加到我的 ~/.zshrc

然后,我删除了 ~/.pyenv/versions/new-virtualenv中部分失败的 virtualenv创建,并重新运行 pyenv virtualenv <name>,它工作得很顺利