Man*_*tis 29 django multithreading django-models
我有一个只能使用的Django模型get_or_create(session=session),其中session是另一个Django模型的外键.
由于我只是通过访问get_or_create(),我想我只会有一个带有会话密钥的实例.但是,我找到了多个具有同一会话密钥的实例.怎么了?这是一种竞争条件,还是get_or_create()以原子方式运作?
Ste*_*ano 41
不,get_or_create 不是原子的.
它首先询问DB是否存在令人满意的行; 数据库返回,python检查结果; 如果它不存在,它会创建它.在get和之间create可以发生任何事情 - 并且get由一些其他代码创建对应于标准的行.
例如,如果用户打开两个页面(或者执行了几个ajax请求),同时这可能导致所有get失败,并且对于所有这些页面create都是新行 - 使用相同的会话,那么对于您的特定问题.
因此,只有get_or_create在数据库通过某些unique/unique_together捕获重复问题时才使用,这样即使多个线程可以到达save(),只有一个会成功,其他的会引发一个IntegrityError,你可以捕捉和处理.
如果您使用get_or_create数据库中不唯一的(一组)字段,您将在数据库中创建重复项,这很少是您想要的.
更一般地说:不要依赖您的应用程序来强制执行唯一性并避免重复数据库!这是数据库的工作!(除非你用一些操作系统有效的锁包装你的关键函数,但我仍然建议使用数据库).
使用这些警告,正确使用get_or_create是一个易于阅读,易于编写的结构,完美地补充了数据库完整性检查.
参考和引用:
rec*_*hak 13
Actualy它不是线程安全的,你可以看一下QuerySet对象的get_or_create方法的代码,basicaly它的作用如下:
try:
return self.get(**lookup), False
except self.model.DoesNotExist:
params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
params.update(defaults)
obj = self.model(**params)
sid = transaction.savepoint(using=self.db)
obj.save(force_insert=True, using=self.db)
transaction.savepoint_commit(sid, using=self.db)
return obj, True
Run Code Online (Sandbox Code Playgroud)
因此,在连续保存实例之前,两个线程可能会发现实例在DB中不存在并开始创建新实例.
线程是一个问题,但get_or_create在MySQL的默认隔离级别中的任何严重用法都会被破坏:
| 归档时间: |
|
| 查看次数: |
6775 次 |
| 最近记录: |