【问题标题】:Avoiding race conditions for a custom get_or_create in Django?避免 Django 中自定义 get_or_create 的竞争条件?
【发布时间】:2015-04-29 05:05:30
【问题描述】:

任何人都可以就以下问题提出建议:

我有一个自定义的 get_or_create 方法,它检查多个字段并在创建时执行一些花哨的操作:

def fancy_get_or_create(name):
    object = self.fancy_get(name)
    if not object:
        object = self.fancy_create(name)
    return object

def fancy_get(name):
    return self.filter(Q(name=name) | Q(alias=name)).first()

def fancy_create(name):
    name = self.some_preprocessing(name)
    return self.create(name=name, alias=name)

有一个竞争条件,一个请求将检查对象是否存在,什么也找不到,然后开始创建它。在该请求完成创建对象之前,另一个请求进来寻找相同的对象,什么也没找到,然后开始创建新对象。这个请求会失败,因为数据库有一些唯一性约束(前一个请求刚刚创建了对象,所以第二个请求会失败)。

有什么方法可以阻止请求 2 在请求 1 完成之前查询数据库?我正在阅读有关事务管理的内容,但它似乎不是解决方案,因为问题不是部分更新(这表明原子事务),而是需要让第二个请求等到第一个请求完成。

谢谢!

更新: 这就是我的选择:

try:
    return self.fancy_get(name) or self.fancy_create(name)
except IntegrityError:
    return self.fancy_get(name)

【问题讨论】:

标签: mysql django race-condition


【解决方案1】:

有两种可行的解决方案:

  1. 使用互斥体,因此只有一个进程可以访问 fancy_get_or_create 同时发挥作用。

  2. 捕获数据库抛出的错误,然后做一些事情:忽略 创建,更新行而不是创建它,抛出一个 异常等

编辑:另一个解决方案可能是执行 INSERT IGNORE 而不仅仅是 INSERT。 https://dev.mysql.com/doc/refman/5.1/en/insert.html

【讨论】:

    猜你喜欢
    • 2014-04-02
    • 1970-01-01
    • 2015-01-30
    • 2010-09-25
    • 1970-01-01
    • 1970-01-01
    • 2010-09-25
    • 2019-06-12
    相关资源
    最近更新 更多