【发布时间】:2018-05-25 11:40:15
【问题描述】:
Django 1.11 版,sqlite3 3.11 版。
我正在使用 WAL 模式和长时间超时:
from django.apps import AppConfig
from django.db.backends.signals import connection_created
class SQLite3Config(AppConfig):
name = 'sqlite3_config'
def ready(self):
connection_created.connect(configure_sqlite)
# noinspection PyUnusedLocal
def configure_sqlite(sender, connection, **_):
if connection.vendor == 'sqlite':
cursor = connection.cursor()
cursor.execute('PRAGMA journal_mode=WAL;')
cursor.execute('PRAGMA busy_timeout=5000;')
我想保留 sqlite3 而不是迁移到 mysql 或 postgres,因为该应用程序很小并且由用户安装在多个服务器上。
我相信 WAL 应该通过序列化它们来允许“并发”写入。当一起接收到小的突发(大约六次)时,观察到“数据库被锁定”问题。
我可以用线程在 shell 中重现问题。 django 模型方法只是简单地设置一个标志并保存模型:
def activate(self):
self.activate = True
self.save()
当我使用线程时,如果我同时启动几个尝试它的线程,我发现它会失败。没有等待,因此不涉及超时。错误发生在 5 秒繁忙超时过去之前(不到两秒):
In [2]: [NGThread(notifier_group.id).start() for notifier_group in NotifierGroup.objects.all()[:2]]
Out[2]: [None, None]
In [3]: [NGThread(notifier_group.id).start() for notifier_group in NotifierGroup.objects.all()[:3]]
Out[3]: [None, None, None]
In [4]: [NGThread(notifier_group.id).start() for notifier_group in NotifierGroup.objects.all()[:4]]
Out[4]: [None, None, None, None]
In [5]: Exception in thread Thread-97:
Traceback (most recent call last):
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/sqlite3/base.py", line 328, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: database is locked
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
self.run()
File "/home/paul/wk/cliosoft/sosadmin/scratch.py", line 41, in run
toggle_active(notifier_group)
File "/home/paul/wk/cliosoft/sosadmin/scratch.py", line 30, in toggle_active
model.activate()
File "/home/paul/wk/cliosoft/sosadmin/notifications/models/notifier_group.py", line 67, in activate
self.save()
File "/home/paul/wk/cliosoft/sosadmin/notifications/models/notifier_group.py", line 33, in save
self.verify()
File "/home/paul/wk/cliosoft/sosadmin/notifications/models/notifier_group.py", line 46, in verify
self.create_notifier(base_spec, model_set, group_event_condition)
File "/home/paul/wk/cliosoft/sosadmin/notifications/models/notifier_group.py", line 57, in create_notifier
notifier.users = self.users.all()
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 534, in __set__
manager.set(value)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 1004, in set
self.add(*new_objs)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 931, in add
self._add_items(self.source_field_name, self.target_field_name, *objs)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 1100, in _add_is
for obj_id in new_ids
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/query.py", line 442, in bulk_create
ids = self._batched_insert(objs_without_pk, fields, batch_size)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/query.py", line 1083, in _batched_insert
self._insert(item, fields=fields, using=self.db)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/query.py", line 1060, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 1099, in execute_sql
cursor.execute(sql, params)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/utils.py", line 80, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/utils.py", line 94, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/utils/six.py", line 685, in reraise
raise value.with_traceback(tb)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/sqlite3/base.py", line 328, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: database is locked
Exception in thread Thread-98:
Traceback (most recent call last):
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/sqlite3/base.py", line 328, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: database is locked
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
self.run()
File "/home/paul/wk/cliosoft/sosadmin/scratch.py", line 41, in run
toggle_active(notifier_group)
File "/home/paul/wk/cliosoft/sosadmin/scratch.py", line 28, in toggle_active
model.deactivate()
File "/home/paul/wk/cliosoft/sosadmin/notifications/models/notifier_group.py", line 72, in deactivate
self.save()
File "/home/paul/wk/cliosoft/sosadmin/notifications/models/notifier_group.py", line 33, in save
self.verify()
File "/home/paul/wk/cliosoft/sosadmin/notifications/models/notifier_group.py", line 46, in verify
self.create_notifier(base_spec, model_set, group_event_condition)
File "/home/paul/wk/cliosoft/sosadmin/notifications/models/notifier_group.py", line 57, in create_notifier
notifier.users = self.users.all()
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 534, in __set__
manager.set(value)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 1004, in set
self.add(*new_objs)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 931, in add
self._add_items(self.source_field_name, self.target_field_name, *objs)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 1100, in _add_is
for obj_id in new_ids
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/query.py", line 442, in bulk_create
ids = self._batched_insert(objs_without_pk, fields, batch_size)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/query.py", line 1083, in _batched_insert
self._insert(item, fields=fields, using=self.db)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/query.py", line 1060, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 1099, in execute_sql
cursor.execute(sql, params)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/utils.py", line 80, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/utils.py", line 94, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/utils/six.py", line 685, in reraise
raise value.with_traceback(tb)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/home/paul/.virtualenvs/sosadmin/lib/python3.5/site-packages/django/db/backends/sqlite3/base.py", line 328, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: database is locked
【问题讨论】:
-
IHMO,我认为您正在尝试在其设计范围之外很好地使用 sqlite3,即使使用一些调度中间件也是如此。根据 sqlite3 文档,一次只能有 1 个写入者,并且该活动也会停止共享(读取)访问。我明白为什么你对使用“更胖”的全功能数据库不感兴趣,但我认为 sqlite3 最适合用于不与其他任何东西共享文件的小型嵌入式系统或应用程序(基本上是单用户访问)。 ref: sqlite.org/lockingv3.html 我应该注意到我几乎每天都在 STRAUX 接收器上使用 sqlite3 数据库。
-
你可能是对的,但是在 sqlite3 中使用 WAL 并且这个应用程序读取很多,写入很少(诚然经常是小突发)让我认为 sqlite3 应该处理它美好的。我对文档的阅读表明,如果这个错误真的是 sqlite3 达到了写入限制,我应该看到超时过去了,但我没有看到。
-
如果您在测试中使用它,这可能是相关的:stackoverflow.com/a/51750516/2015768
标签: django multithreading python-3.x sqlite