support pool_recycle engine create_engine close python mysql sqlalchemy database-deadlocks

python - pool_recycle - Vuelva a intentar el interbloqueo para MySQL/SQLAlchemy



sqlalchemy oracle (2)

¿Usaste código como este?

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

La única manera de realmente manejar los interbloqueos es escribir su código para esperarlos. Esto generalmente no es muy difícil si el código de su base de datos está bien escrito. A menudo, puede poner un try / catch alrededor de la lógica de ejecución de la consulta y buscar un punto muerto cuando se producen errores. Si encuentra uno, lo normal es intentar ejecutar la consulta fallida nuevamente.

Enlaces útiles:

He buscado durante bastante tiempo y no puedo encontrar una solución a mi problema. Estamos utilizando SQLAlchemy junto con MySQL para nuestro proyecto y encontramos varias veces el error temido:

1213, ''Se encontró un interbloqueo al intentar bloquearse; intente reiniciar la transacción ''.

Nos gustaría intentar reiniciar la transacción como máximo tres veces en este caso.

¿Empecé a escribir un decorador que hace esto pero no sé cómo guardar el estado de la sesión antes de que falle y vuelva a intentar la misma transacción? (Como SQLAlchemy requiere una reversión cada vez que se produce una excepción)

Mi trabajo hasta ahora,

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


Realmente no puedes hacer eso con la Session desde afuera. Session tendría que apoyar esto internamente. Implicaría ahorrar mucho estado privado, por lo que puede que no valga la pena.

Olvidé por completo la mayoría de las cosas de ORM en favor de la interfaz de nivel inferior SQLAlchemy Core. Usando esa (o incluso cualquier interfaz dbapi) puede usar de manera trivial su decorador retry_on_deadlock_decorator (vea la pregunta anterior) para hacer un contenedor db.execute tenga en cuenta los db.execute .

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

Y en lugar de

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

tú lo haces

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

que volverá a intentar automáticamente si se produce un punto muerto.