在Django中避免自定义get_or_create的竞争条件?

时间:2015-02-26 17:29:03

标签: mysql django race-condition

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

我有一个自定义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)

存在竞争条件,其中一个请求将检查对象是否存在,什么也找不到,并开始创建它。在该请求完成创建对象之前,另一个请求是查找相同的对象,查找,什么都没有,并开始创建新对象。此请求将失败,因为数据库具有一些唯一性约束(先前的请求刚刚创建了对象,因此第二个请求将失败)。

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

谢谢!

更新: 这就是我的用途:

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

1 个答案:

答案 0 :(得分:2)

有两种可行的解决方案:

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

  2. 捕获数据库引发的错误并执行某些操作:ignore 创建,更新行而不是创建它,抛出一个 例外等。

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