使用数据库事务对多个更新进行分组时,我是否应该在事务中包含SELECT?例如,让我说:
我应该在"记录之前开始交易"阶段,或只是更新?
我使用Postgres / Django transaction.atomic()
,但我认为这不重要。
答案 0 :(得分:4)
简短版本:"它取决于"。
长版:
如果您正在进行读取 - 修改 - 写入循环,那么它不仅必须在事务中,而且您必须SELECT ... FOR UPDATE
您稍后要修改的任何记录。否则,您将面临丢失写入风险,在此情况下,您会覆盖其他人在您阅读记录和编写更新时所做的更新。
SERIALIZABLE
事务隔离也可以帮助解决这个问题。
你真的需要了解并发性和隔离性。不幸的是,唯一的简单,容易"只做X"在不理解的情况下回答是通过锁定所涉及的所有表来开始每个事务。大多数人都不想这样做。
我建议the tx isolation docs阅读(或两个,三个或四个 - 它的硬材料)。尝试并发psql
个会话(多个终端)来创建竞争条件和冲突。
答案 1 :(得分:1)
理想情况下(,如果可能),您将在单 data-modifying CTE中执行所有四个步骤(这会自动发生在内部单笔交易)。
这仍然不排除竞争条件,只是使它们不太可能,因为SELECT .. FOR UPDATE
和后UPDATE
之间的时间范围被最小化。 (是的,你仍然应该使用FOR UPDATE
(or another appropriate locking level)来对抗严重的并发访问下的竞争条件。)
这不是像Django这样的Web框架的典型(低效)方法。但这是优越的方法。它以多种方式优化性能:
在数据修改CTE中使用SELECT .. FOR UPDATE
时,请注意unreferenced CTEs are not executed at all,它也不会按预期锁定行。
数据修改CTE的代码示例: