基本上get_or_create 可能会失败 -如果你查看其来源,就会发现它是:get,if-problem:save + some_trickery,if-still-problem:再次获取,if-still-problem:投降并加薪。
这意味着,如果有两个同时运行的线程(或进程)同时运行
create_or_update_myobj,都试图
get_or_create相同的对象,则:
- 第一个线程试图获取它-但它尚不存在,
- 因此,线程尝试创建它,但是在创建对象之前…
- …第二个线程试图获取它-这显然失败了
- 现在,由于MySQLdb数据库连接的默认AUTOCOMMIT = OFF和REPEATABLE READ可序列化级别,两个线程都冻结了它们对MyObj表的视图。
- 随后,第一个线程创建其对象并优雅地返回它,但是…
- …第二个线程无法创建任何东西,因为它将违反
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
该问题还有第二种解决方案-使用READ COMMITED隔离级别,而不是REPEATABLE READ。但是它的测试较少(至少在MySQL中是这样),因此可能存在更多的错误/问题-但至少它允许将视图绑定到事务,而无需在中间提交。



