在 Django 中避免自定义 get_or_create 的竞争条件?
Avoiding race conditions for a custom get_or_create in Django?
任何人都可以就以下问题提出建议:
我有一个自定义 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)
有两个可行的解决方案:
使用互斥锁,这样只有一个进程可以访问 fancy_get_or_create
同时发挥作用。
捕获数据库抛出的错误并做一些代替:忽略
创建,更新行而不是创建它,抛出一个
异常等
编辑:另一个解决方案可能是执行 INSERT IGNORE 而不仅仅是 INSERT。 https://dev.mysql.com/doc/refman/5.1/en/insert.html
任何人都可以就以下问题提出建议:
我有一个自定义 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)
有两个可行的解决方案:
使用互斥锁,这样只有一个进程可以访问 fancy_get_or_create 同时发挥作用。
捕获数据库抛出的错误并做一些代替:忽略 创建,更新行而不是创建它,抛出一个 异常等
编辑:另一个解决方案可能是执行 INSERT IGNORE 而不仅仅是 INSERT。 https://dev.mysql.com/doc/refman/5.1/en/insert.html