最近数据库出现了莫名的BUG,一条记录会同时创建两次。
为了解决这个问题,首先看了一下代码,代码用了get_or_create()
这个方法,翻看了源码:
def get_or_create(self, defaults=None, **kwargs):
"""
Look up an object with the given kwargs, creating one if necessary.
Return a tuple of (object, created), where created is a boolean
specifying whether an object was created.
"""
lookup, params = self._extract_model_params(defaults, **kwargs)
# The get() needs to be targeted at the write database in order
# to avoid potential transaction consistency problems.
self._for_write = True
try:
return self.get(**lookup), False
except self.model.DoesNotExist:
return self._create_object_from_params(lookup, params)
原来这个方法不是原子的,如果并发操作会出现问题(就像我的创建了两次)。不过这个方法的名字太“原子”了,会让人误以为是线程安全的,如果改成get_or_create_unsafely()
可能会让人谨慎起来。
接着,我查看了一下日志,果真是有并发的请求,难怪会出现这样的问题。
解决方案:
- 配合事务一起使用
- 在model层加限制
unique
或unique_together