我已经搜索了很长一段时间,但找不到解决我的问题的方法。我们在项目中将 SQLAlchemy 与 MySQL 结合使用,并且多次遇到可怕的错误:
1213, '尝试获取锁定时发现死锁;尝试重新启动事务”。
在这种情况下,我们最多尝试重新启动交易三次。
我已经开始编写一个装饰器来执行此操作,但我不知道如何在失败之前保存会话状态并在失败之后重试相同的事务? (因为 SQLAlchemy 需要在引发异常时回滚)
到目前为止我的工作,
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
你真的不能用Session
从外部。Session
必须在内部支持这一点。这将涉及保存大量私有状态,因此这可能不值得您花时间。
我完全放弃了大多数 ORM 内容,转而使用较低级别的 SQLAlchemy Core 接口。使用它(甚至任何 dbapi 接口),您可以轻松地使用您的retry_on_deadlock_decorator
装饰器(参见上面的问题)以进行重试感知db.execute
包装纸。
@retry_on_deadlock_decorator
def deadlock_safe_execute(db, stmt, *args, **kw):
return db.execute(stmt, *args, **kw)
而不是
db.execute("UPDATE users SET active=0")
you do
deadlock_safe_execute(db, "UPDATE users SET active=0")
如果发生死锁,它将自动重试。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)