Django数据库事务和死锁

时间:2012-06-26 18:13:47

标签: python mysql django mysql-python django-orm

当使用带有多个进程/工作程序的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()

有人能发现这里可能出现的问题吗?

1 个答案:

答案 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
      }
  }