该代码应获取或创建一个对象,并在必要时对其进行更新。该代码已在网站上投入生产。
在某些情况下-当数据库繁忙时-它会引发异常“ DoesNotExist:MyObj匹配查询不存在”。
# Model: class MyObj(models.Model): thing = models.ForeignKey(Thing) owner = models.ForeignKey(User) state = models.BooleanField() class Meta: unique_together = (('thing', 'owner'),) # Update or create myobj @transaction.commit_on_success def create_or_update_myobj(owner, thing, state) try: myobj, created = MyObj.objects.get_or_create(owner=user,thing=thing) except IntegrityError: myobj = MyObj.objects.get(owner=user,thing=thing) # Will sometimes throw "DoesNotExist: MyObj matching query does not exist" myobj.state = state myobj.save()
我在ubuntu上使用了一个innodb mysql数据库。
我如何安全地处理此问题?
基本上get_or_create 可能会失败 -如果你查看其来源,就会发现它是:get,if-problem:save + some_trickery,if-still-problem:再次获取,if-still-problem:投降并加薪。
这意味着,如果有两个同时运行的线程(或进程)同时运行create_or_update_myobj,都试图get_or_create相同的对象,则:
create_or_update_myobj
get_or_create
unique
get
因此,如果你想安全地进行get_or_create任何操作,请尝试以下操作:
@transaction.commit_on_success def my_get_or_create(...): try: obj = MyObj.objects.create(...) except IntegrityError: transaction.commit() obj = MyObj.objects.get(...) return obj
该问题还有第二种解决方案-使用READ COMMITED隔离级别,而不是REPEATABLE READ。但是它的测试较少(至少在MySQL中是这样),因此可能存在更多的错误/问题-但至少它允许将视图绑定到事务,而无需在中间提交。