1

複数のプロセス/ワーカーで Gunicorn を使用して Django を実行すると、手動の MySQL データベース トランザクションの一部でデッドロックの問題が発生します。

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

私のセットアップは複数のデータベースを使用しており、私の関数は、呼び出されたときに使用するデータベースを渡す必要があります。このため、データベースを引数としてハードコーディングする必要があるため、標準のDjango トランザクション デコレータを使用できません。デコレーター コードを調べて、トランザクションがどのように管理されているかを確認しました。関数は次のようになります。

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

ここで何がうまくいかないのか誰にもわかりますか?

4

1 に答える 1

4

withより明確なスタイルの構文を使用したい場合があることに注意してください。以下は上記のコードと同じですが、よりピトン的です。

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あり、ほとんどの用途には厳しすぎます。(オラクルのデフォルトは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
      }
  }
于 2013-03-05T20:10:58.053 に答える