在django和mysql设置中死锁后,Hook可用于自动重试

时间:2013-06-19 05:23:52

标签: mysql django mysql-python

我在Django中使用带有mysql数据库的innoDB表。在调查错误期间

  

OperationalError:(1213,'尝试获取锁定时发现死锁;尝试重启事务')

我从this answer发现了Omry。在答案的最后部分,他建议

  

客户端应自动重试。

我试图将这个逻辑放在代码中,但同时在django中可以直接使用任何钩子。这样我们就可以设置3次自动重试,以防死锁。此外,如果有人可以举例说明将这个逻辑放在代码中(我使用的是django过滤器)。

PS:我可以在Omry的答案下面问这个问题,但我低于50分并想把它带给django专家。

1 个答案:

答案 0 :(得分:7)

这是一个老问题,但由于没有人发布答案,所以就是这样。

为了在发生死锁时重试查询,我所做的就是修补django的CursorWrapper类的方法“execute”。无论何时进行查询,都会调用此方法,因此它将在整个ORM中运行,您不必担心项目中的死锁:

import django.db.backends.utils
from django.db import OperationalError
import time

original = django.db.backends.utils.CursorWrapper.execute

def execute_wrapper(*args, **kwargs):
    attempts = 0
    while attempts < 3:
        try:
            return original(*args, **kwargs)
        except OperationalError as e:
            code = e.args[0]
            if attempts == 2 or code != 1213:
                raise e
            attempts += 1
            time.sleep(0.2)

django.db.backends.utils.CursorWrapper.execute = execute_wrapper

上面的代码是:它将尝试运行查询,如果抛出一个错误代码为1213(死锁)的OperationalError,它将等待200毫秒并再次尝试。它将执行此操作3次,如果3次后问题仍未解决,则会引发原始异常。

当django项目被加载到内存中时,应该执行此代码,因此放置它的好地方是在任何应用程序的__init__.py文件中(我放在__init__.py文件中我的项目的主目录 - 与你的django项目同名的那个。)

希望这有助于将来的任何人。