如果您依靠“自动交易”来提供锁定 在select_for_update()和后续的写操作之间 - 一个 极其脆弱的设计,但仍然可能 - 你必须包装 atomic()中的相关代码。从Django 1.6.3开始,用。执行查询 自动提交模式下的select_for_update()将引发一个 TransactionManagementError。
为什么这被认为是脆弱的?我原以为这会导致正确的交易。
答案 0 :(得分:9)
select_for_update
并不脆弱。
我写了那个"如果你依赖"自动交易""然后,当您从1.5升级到1.5时,需要检查代码。
如果您不依赖&#34;自动交易&#34;,如果概念没有敲响钟声,那么您就不需要做任何事情。< / p>
正如 yuvi 的答案所指出的那样(非常好,谢谢!)Django会在遇到无效代码时引发异常。在TransactionManagementError
select_for_update
看到{{1}}之前,我们无需考虑这一点。
答案 1 :(得分:4)
答案即将到来,在select_for_update的文档中(强调我的):
在自动提交模式下使用select_for_update评估查询集是一个 错误,因为行未被锁定。如果允许,会这样 促进数据损坏,很容易被调用, 在任何事务之外,代码期望在一个事务中运行。
换句话说,autocommit
和select_for_update
之间存在矛盾的行为,这会导致数据损坏。这是他们首次提出解决这个问题的django developer's discussion,引用(再次强调我的):
[...]在Oracle下,在自动提交模式下,自动提交发生 执行命令后立即执行 - 尝试获取 结果无法在单独的事务中完成。
但是,任何后端,自动提交模式下的select-for-update 没什么意义。即使它没有破坏(就像它一样 Oracle),它并没有真正锁定任何东西。所以,IMO,执行一个 查询是自动提交模式下的select-for-update可能是en 错误,以及可能导致数据损坏错误的错误。
所以我建议我们改变select-for-update查询的行为, 错误[...]这是一个向后不兼容的变化[...] 这些项目应该是值得庆幸的 - 他们正在运行 现在暴露的微妙错误 - 但仍然。
因此,这是一个仅限Oracle的错误,它显示了与所有后端相关的更深层问题,因此他们决定在django中将此错误。
另一方面, Atomic
仅在验证没有错误后才将数据提交到数据库,从而解决了问题。
答案 2 :(得分:3)
Aymeric通过电子邮件澄清这样的设计很脆弱,因为它依赖于Django 1.5的隐式事务形成的隐式事务边界。
select_for_update(...)
more_code()
save()
此代码适用于简单的情况,但如果more_code()
导致对数据库的写操作,则事务将关闭,从而产生意外行为。
强制用户指定事务边界也会产生更清晰的代码。