我遇到了与sqlalchemy一起使用的InnoDB表中的死锁问题。
sqlalchemy.exc.InternalError:(mysql.connector.errors.InternalError)1213(40001):尝试锁定时发现死锁;尝试重新启动交易。
我已经序列化了访问权限,但仍然遇到死锁错误。
此代码在每个函数的第一次调用时执行。每个线程和进程都应该在这里等待,直到它获得锁定。随着选择器被移除,它被简化了。
# The work with the index -1 always exists.
f = s.query(WorkerInProgress).with_for_update().filter(
WorkerInProgress.offset == -1).first()
我已将代码缩减到最小状态。我目前只在方法next_slice上运行并发调用。会话处理,回滚和deadloc处理在外部处理。
即使所有访问都被序列化,我也会遇到死锁。我也尝试在offset == -1实体中增加重试计数器。
def next_slice(self, s, processgroup_id, itemcount):
f = s.query(WorkerInProgress).with_for_update().filter(
WorkerInProgress.offset == -1).first()
#Take first matching object if available / Maybe some workers failed
item = s.query(WorkerInProgress).with_for_update().filter(
WorkerInProgress.processgroup_id != processgroup_id,
WorkerInProgress.processgroup_id != 'finished',
WorkerInProgress.processgroup_id != 'finished!locked',
WorkerInProgress.offset != -1
).order_by(WorkerInProgress.offset.asc()).limit(1).first()
# *****
# Some code is missing here. as it's not executed in my testcase
# Fetch the latest item and add a new one
item = s.query(WorkerInProgress).with_for_update().order_by(
WorkerInProgress.offset.desc()).limit(1).first()
new = WorkerInProgress()
new.offset = item.offset + item.count
new.count = itemcount
new.maxtries = 3
new.processgroup_id = processgroup_id
s.add(new)
s.commit()
return new.offset, new.count
我不明白为什么会发生死锁。
我通过在一个查询中获取所有项目来减少死锁,但仍然会出现死锁。也许有人可以帮助我。
答案 0 :(得分:2)
最后我解决了我的问题。这些都在文档中,但我必须先了解它。
如果交易失败,请务必重新发布交易 僵局。死锁并不危险。再试一次。
我通过改变这部分的架构解决了我的问题。我仍然遇到很多死锁,但它们几乎都出现在短期运行的方法中。 我把工人桌分成了一个锁定和一个非锁定的部分。锁定部分上的操作现在非常短,并且在get_slice,finish_slice和fail_slice操作期间没有数据处理。
具有数据处理的事务部分现在处于非锁定部分,并且没有对表行的并发访问。结果存储在finish_slice和fail_slice中,并存储到锁定表中。
最后我也发现了stackoverflow的一个很好的描述。确定正确的搜索词后。 http://dev.mysql.com/doc/refman/5.7/en/innodb-deadlocks-handling.html