问题:
给定表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。