问题:
给定表table_a
和table_b
,我需要在更新时可靠地(同时)执行这样的操作table_a
:
SELECT
一些行来自table_a
.- 在应用程序代码中计算一些东西。
UPDATE
中的一排table_b
。
我需要防止发生这样的事情(称之为场景 A),table_b
最终反映的是旧版本table_a
:
worker1
从中获取行table_a
。table_a
已更新。worker2
从中获取行table_a
。worker2
更新table_b
。worker1
更新table_b
。
但这很好(称之为场景 B),因为table_b
最终处于正确的状态:
worker1
从中获取行table_a
。table_a
已更新。worker2
从中获取行table_a
。worker1
更新table_b
。worker2
更新table_b
。
交易:
一种解决方案是将整个事物包装在REPEATABLE READ
事务中。thenworker1
的事务在场景 A 中worker2
失败,在场景 B 中的事务失败。没有办法区分场景,唯一的选择是重试失败的事务。
但在这两种情况下都是浪费:在场景 A 中,我们宁愿不重试worker1
的事务,因为table_b
已经完全更新了。在场景 B 中,我们宁愿worker2
一开始就不要失败的事务,因为它正在做正确的事情。
行标记:
table_b
如果我们从一开始就知道行的主键( :b_id
) 并且每个工作人员都有一些唯一的 ID ( :worker_id
),我们可以尝试其他方法。在步骤 1 之前添加一mark
列table_b
并让每个工作人员执行此操作:
UPDATE table_b SET mark = :worker_id WHERE id = :b_id;
然后在第 3 步中添加一个WHERE
子句:
UPDATE table_b SET ... WHERE ... AND mark = :worker_id;
现在worker1
,根据需要,在两种情况下都不会在步骤 3 中更新任何行。
行标记在这里是一种合理的方法吗?我缺少什么缺点?这个问题的“规范”解决方案是什么?
澄清:我正在使用 PostgreSQL。