5

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

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

我从Omry 那里看到了这个答案。在他建议的答案的最后一部分

客户端应自动重试。

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

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

4

1 回答 1

8

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

为了在发生死锁时重试查询,我所做的是我猴子修补了 django 的 CursorWrapper 类的“执行”方法。每当进行查询时都会调用此方法,因此它将在整个 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 项目)。

希望这对将来的任何人都有帮助。

于 2015-12-14T13:11:05.447 回答