python - SQLAlchemy/MySQL 序列化访问死锁

标签 python mysql sqlalchemy deadlock

我在使用 sqlalchemy 的 InnoDB 表中遇到死锁是个大问题。

sqlalchemy.exc.InternalError: (mysql.connector.errors.InternalError) 1213 (40001): Deadlock found when trying to get lock; try restarting transaction.

我已经序列化了访问,但仍然出现死锁错误。

此代码在每个函数的第一次调用时执行。每个线程和进程都应该在这里等待,直到它获得锁。它被简化了,因为选择器被删除了。

    # The work with the index -1 always exists.
    f = s.query(WorkerInProgress).with_for_update().filter(
        WorkerInProgress.offset == -1).first()

我已将我的代码减少到最小状态。我目前只对 next_slice 方法运行并发调用。 session 处理、回滚和死锁处理在外部处理。

即使所有访问都是序列化的,我也会遇到死锁。我也尝试在 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

我不明白为什么会出现死锁。

我通过在一个查询中获取所有项目减少了死锁,但仍然遇到死锁。也许有人可以帮助我。

最佳答案

终于解决了我的问题。文档里都有,但是我得先了解一下。

Always be prepared to re-issue a transaction if it fails due to deadlock. Deadlocks are not dangerous. Just try again.

Source: http://dev.mysql.com/doc/refman/5.7/en/innodb-deadlocks-handling.html

我已经通过更改这部分的架构解决了我的问题。我仍然遇到很多死锁,但它们几乎出现在短运行方法中。 我已将我的工作表拆分为锁定部分和非锁定部分。锁定部分的操作现在非常短,在 get_slice、finish_slice 和 fail_slice 操作期间没有处理任何数据。

具有数据处理的事务部分现在处于非锁定部分并且不能并发访问表行。结果存储在 finish_slice 和 fail_slice 到锁定表中。

最后我在 stackoverflow 上也找到了一个很好的描述。确定正确的搜索词后。 https://stackoverflow.com/a/2596101/5532934

关于python - SQLAlchemy/MySQL 序列化访问死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39190752/

相关文章:

python - 限制 os.walk 遍历的嵌套目录数量

mysql - Condition with join 类似于 where condition after join

python - 在 sqlalchemy 中定义列 func.count 的名称

python - 如何替换sqlalchemy查询中的列

python - 如何优化这段代码?我想解决 DeadlineExceededError 问题

python - 读取后删除文件

python 套接字,sock.connect 错误

php - 我在使用 mysqli free() 成员函数时遇到问题

mysql - Sqoop 导出到 Aurora RDS 的速度非常慢

python - 如何减少 sqlalchemy 用于连接数据库和选择数据的时间