2014-05-16 29 views
16

Szukałem już od jakiegoś czasu i nie mogę znaleźć rozwiązania mojego problemu. Jesteśmy przy użyciu SQLAlchemy w połączeniu z MySQL do naszego projektu i mamy do czynienia kilka razy bał błąd:Spróbuj ponownie w przypadku zakleszczenia MySQL/SQLAlchemy

1213, 'Deadlock found when trying to get lock; try restarting transaction'.

Chcielibyśmy, aby spróbować ponownie uruchomić transakcję co najwyżej trzy razy w tym przypadku.

Zacząłem pisać dekorator, który robi to, ale nie wiem, jak zapisać stan sesji przed niepowodzeniem i ponowić tę samą transakcję po nim? (Jak SQLAlchemy wymaga cofnięcia, gdy wyjątek jest podniesiona)

mojej pracy tak daleko,

def retry_on_deadlock_decorator(func): 
    lock_messages_error = ['Deadlock found', 'Lock wait timeout exceeded'] 

    @wraps(func) 
    def wrapper(*args, **kwargs): 
     attempt_count = 0 
     while attempt_count < settings.MAXIMUM_RETRY_ON_DEADLOCK: 
      try: 
       return func(*args, **kwargs) 
      except OperationalError as e: 
       if any(msg in e.message for msg in lock_messages_error) \ 
         and attempt_count <= settings.MAXIMUM_RETRY_ON_DEADLOCK: 
        logger.error('Deadlock detected. Trying sql transaction once more. Attempts count: %s' 
           % (attempt_count + 1)) 
       else: 
        raise 
      attempt_count += 1 
    return wrapper 
+1

Czy mogę ci pomóc? Albo znalazłeś inne rozwiązanie. Udostępnij dowolny wynik. –

Odpowiedz

0

Czy użyć kodu jak to?

try: 

    Perform table transaction 
    break 
except: 
    rollback 
    delay 
    try again to perform table transaction 

The only way to truly handle deadlocks is to write your code to expect them. This generally isn't very difficult if your database code is well written. Often you can just put a try/catch around the query execution logic and look for a deadlock when errors occur. If you catch one, the normal thing to do is just attempt to execute the failed query again.

Przydatne linki:

2

Naprawdę nie można zrobić to z Session z zewnątrz. Session musiałaby to wewnętrznie wspierać. Obejmowałoby to oszczędzanie dużej ilości prywatnego państwa, więc może nie być warte twojego czasu.

Całkowicie zrezygnowałem z większości ORMów na rzecz niższego poziomu interfejsu SQLAlchemy Core. Korzystając z tego (lub nawet dowolnego interfejsu dbapi), możesz w łatwy sposób użyć dekoratora retry_on_deadlock_decorator (patrz pytanie powyżej), aby utworzyć opakowanie typu.

@retry_on_deadlock_decorator 
def deadlock_safe_execute(db, stmt, *args, **kw): 
    return db.execute(stmt, *args, **kw) 

I zamiast

db.execute("UPDATE users SET active=0") 

zrobić

deadlock_safe_execute(db, "UPDATE users SET active=0") 

który będzie próbował automatycznie jeśli impas dzieje.

Powiązane problemy