此代码应该获取或创建一个对象,并在必要时更新它.该代码在网站上正在生产中使用.
在某些情况下 - 当数据库繁忙时 - 它将抛出异常"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()
Run Code Online (Sandbox Code Playgroud)
我在ubuntu上使用innodb mysql数据库.
我该如何安全地处理这个问题?
Tom*_*ski 41
这可能是与此问题相同的问题:
基本上get_or_create 可能会失败 - 如果你看看它的来源,你会看到它是:get,if-problem:save + some_trickery,if-still-problem:get get,if-still-problem:derender and raise .
这意味着如果有两个同时运行的线程(或进程)create_or_update_myobj,都尝试get_or_create同一个对象,那么:
unique约束get第二个线程没有看到第一个线程中创建的对象,因为MyObj表的冻结视图所以,如果你想安全地做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
Run Code Online (Sandbox Code Playgroud)
还有第二个解决问题的方法 - 使用READ COMMITED隔离级别,而不是REPEATABLE READ.但它的测试较少(至少在MySQL中),因此可能存在更多的错误/问题 - 但至少它允许将视图绑定到事务,而不是在中间提交.
这里有一些关于MySQL和Django的好博客文章(不是我的),与这个问题有关:
http://www.no-ack.org/2010/07/mysql-transactions-and-django.html
http://www.no-ack.org/2011/05/broken-transaction-management-in-mysql.html
| 归档时间: |
|
| 查看次数: |
8932 次 |
| 最近记录: |