Django DB transactions and deadlocks

三世轮回 提交于 2019-12-11 07:37:17

问题


When running Django with Gunicorn with multiple processes/workers I'm getting a deadlock issue with some of my manual MySQL database transactions.

DatabaseError(1205, 'Lock wait timeout exceeded; try restarting transaction')

My setup uses multiple databases, and my function needs to be passed the database to use when it's called. For this reason, I can't use the standard Django transaction decorators as the db needs to be hard-coded as an argument. I've inspected the decorator code to look at how transactions are managed, and my function looks like this:

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()

Can anyone spot what may be going wrong here?


回答1:


Note you might want to use the more clear with-style syntax. The following should be identical to your code above, but more 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)

or with a decorator

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)

That does not solve your deadlock problem though..

You might have success with lowering your transaction isolation level. This defaults on mysql to REPEATABLE READ wich is too strict for most usages. (oracle defaults to READ COMMITTED')

You can achieve this by adding this to your 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
      }
  }


来源:https://stackoverflow.com/questions/11213481/django-db-transactions-and-deadlocks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!