117

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

OperationalError: database is locked

我已经重新启动了服务器,但错误仍然存​​在。这到底是怎么回事?

4

26 回答 26

124

来自 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

于 2010-07-03T21:33:56.000 回答
57

就我而言,这是因为我从 SQLite 浏览器打开数据库。当我从浏览器关闭它时,问题就消失了。

于 2016-09-12T11:21:35.263 回答
42

造成这种情况的实际原因通常是 python 或 django shell 已经打开了对 DB 的请求,但没有正确关闭;杀死您的终端访问通常可以释放它。我今天在运行命令行测试时遇到了这个错误。

编辑:我对此定期进行投票。如果您想在不重新启动终端的情况下终止访问,那么您可以从命令行执行以下操作:

from django import db
db.connections.close_all()
于 2013-10-22T11:52:38.507 回答
41

我不同意@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()在完成(甚至是只读的)查询后尽快执行。

这里有更多细节

于 2018-11-25T17:43:40.077 回答
8

正如其他人所说,还有另一个进程正在使用 SQLite 文件并且没有关闭连接。如果您使用的是 Linux,您可以使用以下命令查看哪些进程正在使用该文件(例如db.sqlite3fuser

$ sudo fuser -v db.sqlite3
                     USER        PID ACCESS COMMAND
/path/to/db.sqlite3:
                     user        955 F....  apache2

如果要停止进程以释放锁,请使用fuser -kwhich 将KILL信号发送到访问文件的所有进程:

sudo fuser -k db.sqlite3

请注意,这是危险的,因为它可能会停止生产服务器中的 Web 服务器进程。

感谢@cz-game 指出fuser

于 2019-05-06T07:34:41.460 回答
4

在 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())
于 2019-09-06T18:14:33.957 回答
4

使用保存在 WSL (\\wsl$ ...) 下的数据库文件并运行 Windows python 解释器时出现此错误。

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

于 2021-05-15T14:44:49.523 回答
2

如果您通过 pycharm 通过 dbbrowser 插件连接到您的 sqlite 数据库,也会发生这种情况。断线就能解决问题

于 2019-01-07T15:21:21.720 回答
2

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

于 2019-02-06T02:59:03.263 回答
2

我有同样的错误!原因之一是数据库连接未关闭。因此,检查未关闭的数据库连接。另外,在关闭连接之前检查您是否已提交数据库。

于 2019-09-02T13:11:33.820 回答
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
于 2020-02-14T22:50:48.857 回答
1

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

于 2020-05-06T21:35:54.520 回答
1

我发现这可以满足我的需要。(线程锁定) 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(五秒)。

于 2020-08-18T04:04:14.453 回答
1

就我而言,我添加了一条手动保存的新记录,然后再次通过 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)>]>
于 2020-11-21T08:54:45.747 回答
1

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

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

于 2021-06-05T09:03:59.840 回答
1

我在我的烧瓶应用程序中遇到了这个问题,因为我在 SQLite 浏览器中打开了数据库并忘记编写更改。

如果您还在 SQLite 浏览器中进行了任何更改,请单击写入更改,一切都会好起来的

在此处输入图像描述

于 2021-10-19T17:19:40.607 回答
0

就我而言,我没有保存在 SQLite 浏览器中执行的数据库操作。保存它解决了这个问题。

于 2018-09-13T21:41:20.320 回答
0

一个非常不寻常的场景,发生在我身上。

有无限递归,不断创建对象。

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

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

    return self.create(request, *args, **kwargs)
于 2020-04-19T20:33:57.670 回答
0

这里已经有很多答案了,即使我想分享我的案例,这可能会对某人有所帮助..

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

于 2020-06-27T09:02:40.490 回答
0

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

于 2020-08-04T13:09:58.330 回答
0

实际上我遇到了同样的问题,当我使用“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,即使你是在开发环境中工作。

我希望这对你有帮助。

于 2021-03-23T04:27:50.740 回答
0

尝试在 SQLite 中创建新表时出现此错误,但session对象包含未提交(尽管已刷新)的更改。

确保:

  1. 在创建新表之前提交会话
  2. 关闭所有会话并在新连接中执行表创建
  3. ...
于 2021-05-11T08:39:46.117 回答
0

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

于 2022-01-21T12:52:10.363 回答
-1

更新django 版本 2.1.7

sqlite3.OperationalError: database is locked使用pytestwith得到了这个错误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 ... == ....
于 2019-04-17T21:38:45.057 回答
-2

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

于 2020-08-04T22:29:40.010 回答
-10

试试这个命令:

sudo fuser -k 8000/tcp
于 2018-01-15T11:56:12.480 回答