当使用带有多个进程/工作程序的Gunicorn运行Django时,我的一些手动MySQL数据库事务会遇到死锁问题。
DatabaseError(1205, 'Lock wait timeout exceeded; try restarting transaction')
我的设置使用多个数据库,我的函数需要传递给数据库才能在调用时使用。出于这个原因,我不能使用标准Django transaction decorators,因为db需要硬编码作为参数。我检查了装饰器代码,看看如何管理事务,我的函数看起来像这样:
from django.db import connections
def process(self, db, data):
# Takeover transaction management
connections[db].enter_transaction_management(True)
connections[db].managed(True)
# Process
try:
# do things with my_objects...
for obj in my_objects:
obj.save(using=db)
connections[db].commit()
except Exception as e:
connections[db].rollback()
finally:
connections[db].leave_transaction_management()
有人能发现这里可能出现的问题吗?
答案 0 :(得分:3)
请注意,您可能希望使用更清晰的with
- 样式语法。以下内容应与上面的代码相同,但更多的是pytonic。
from django.db import transaction
from __future__ import with_statement
def process(self, db, data):
with transaction.commit_on_success(using=db):
# do things with my_objects...
for obj in my_objects:
obj.save(using=db)
或装饰者
from django.db import transaction
@transaction.commit_on_success(using=db)
def process(self, db, data):
# do things with my_objects...
for obj in my_objects:
obj.save(using=db)
但这并不能解决你的死锁问题..
您可能会成功降低事务隔离级别。这默认为mysql到REPEATABLE READ
,对于大多数用法来说太严格了。 (oracle默认为READ COMMITTED
')
您可以通过将此添加到settings.py
MYSQL_DATABASE_OPTIONS = {'init_command': 'SET storage_engine=INNODB; SET
SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;'}
DATABASES = {
'default': { # repeat for each db
'ENGINE': ... etc
...
...
'OPTIONS': MYSQL_DATABASE_OPTIONS
}
}