OperationalError:数据库已锁定

时间:2010-07-03 21:26:43

标签: python django database sqlite locked

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

OperationalError: database is locked

我重新启动了服务器,但错误仍然存​​在。它有什么关系?

23 个答案:

答案 0 :(得分:56)

来自django doc:

  

SQLite意味着轻量级   数据库,因此不能支持   高并发性。   OperationalError:数据库已锁定   错误表明您的申请   正在经历更多的并发性   sqlite可以默认处理   组态。这个错误意味着   一个线程或进程具有独占权   锁定数据库连接和   另一个线程超时等待   锁被释放。

     

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

     

如果您收到此错误,则可以   通过以下方式解决:

     

切换到另一个数据库后端。   在某个时刻,SQLite也变得如此   “lite”用于实际应用,   和这些类型的并发错误   表明你已达到这一点。

     

重写代码以减少   并发并确保数据库   交易是短暂的。

     

增加默认超时值   设置超时数据库选项   optionoption

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

答案 1 :(得分:23)

实际的原因通常是python或django shell已经向DB打开了一个请求并且没有正确关闭;杀死你的终端访问通常会释放它。我今天在运行命令行测试时遇到此错误。

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

from django import db
db.connections.close_all()

答案 2 :(得分:13)

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

答案 3 :(得分:4)

我不同意@Patrick的回答,该回答通过引用此文档,将OP的问题(Database is locked)隐式链接到此:

  

切换到另一个数据库后端。在某些时候,SQLite对于实际的应用程序来说太“精简”了,这些并发错误表明您已经达到了这一点。

将这个问题归咎于SQlite有点“太容易了”。除非您有一个非常繁忙的服务器同时具有成千上万的连接,否则Database is locked错误的原因可能是API的错误使用,而不是SQlite固有的问题“轻”。。这是有关Implementation Limits for SQLite的更多信息。


现在解决方案:

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

  • 有人通过写操作访问数据库
  • 另一个正在以只读方式访问数据库

解决方案:在进行了(甚至是只读的)查询后,总是尽快执行cursor.close()

Here are more details

答案 4 :(得分:3)

在帕特里克答案中所链接的帮助信息无法(显然)解决的情况下,我遇到了此错误消息。

当我使用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())

答案 5 :(得分:2)

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

答案 6 :(得分: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

答案 7 :(得分:1)

如果通过pycharm通过dbbrowser插件连接到sqlite db,也可能发生这种情况。断开连接将解决问题

答案 8 :(得分:1)

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

答案 9 :(得分:1)

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

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

答案 10 :(得分:1)

我发现这可以满足我的需求。 (线程锁定)YMMV conn = sqlite3.connect(数据库,超时= 10)

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

sqlite3.connect(数据库[,超时,detect_types,isolation_level,check_same_thread,factory,cached_statements,uri])

当通过多个连接访问数据库,并且其中一个进程修改了数据库时,SQLite数据库将被锁定,直到提交该事务为止。 timeout参数指定连接应等待多长时间才能引发锁,直到引发异常为止。超时参数的默认值为5.0(五秒)。

答案 11 :(得分:0)

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

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

答案 12 :(得分:0)

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

答案 13 :(得分:0)

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

确保:

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

答案 14 :(得分:0)

实际上我遇到了同样的问题,当我使用“transaction.atomic() 和 select_for_update()”时,我收到错误消息“OperationalError:数据库被锁定”,

经过多次尝试/搜索/阅读 django 文档, 我从 SQLite 本身发现问题,它不支持 select_for_update 方法,如 django DOC 所说,请查看以下网址并深入阅读:

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

,当我迁移到 MySQL 时一切正常。

因为 django DOCs 还说当数据库超时发生时可能会发生“数据库被锁定”, 他们建议您通过设置以下选项来更改数据库超时:

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

最后,即使你在开发环境中工作,我还是建议你使用 MySQL/PostgreSQL。

希望对你有帮助。

答案 15 :(得分: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)>]>

答案 16 :(得分:0)

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

答案 17 :(得分:0)

这里已经有很多答案,即使我想分享我的情况,这也可能对某人有所帮助。

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

答案 18 :(得分:0)

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

存在无限递归,因此不断创建对象。

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

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

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

答案 19 :(得分:0)

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

答案 20 :(得分:0)

更新 django版本2.1.7

我将sqlite3.OperationalError: database is lockedpytest一起使用时出现了此错误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 ... == ....

答案 21 :(得分:-1)

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

答案 22 :(得分:-7)

尝试此命令:

sudo fuser -k 8000/tcp