【发布时间】:2021-08-14 05:13:11
【问题描述】:
举个例子:
Operation Signal Value Balance
1 + 100.00 100.00
2 + 50.00 150.00
3 + 10.00 160.00
现在我有两个并发事务,它们执行最后一个操作,添加值然后保存(插入)。这些值永远不会更新。
交易 1
获取最后一个操作 (3) 并将其锁定为“更新”并插入
Operation Signal Value Balance
1 + 100.00 100.00
2 + 50.00 150.00
3 + 10.00 160.00
4 + 10.00 170.00
交易 2
获取最后一个操作并将其锁定“以进行更新”。由于第一个事务有一个“for update”锁,它等待获取最新的。在此示例中,事务 2 在事务 1 结束之前开始。
从 postgresql 返回的实际行是#3(在第一个锁被释放之后)。所以它最终是这样的:
Operation Signal Value Balance
1 + 100.00 100.00
2 + 50.00 150.00
3 + 10.00 160.00
4 + 10.00 170.00
5 + 10.00 170.00
所以余额是 170.00。期望是 180.00。
这是 READ_COMMITTED 事务模式。
在 SERIALIZABLE 模式下,事务 2 会引发有关并发的错误。
我尝试了以下方法:
- 用“for update”选择了最新的行;
- 选择了一行
this_is_the_last = true"for update",将其更改为false,然后插入一个带有this_is_the_last = true的新行。 PostgreSQL 最终会返回带有this_is_the_last = false的行,即使它不是(在事务 1 释放for update锁之后的事务 2 上)。
有没有办法进行行级锁定并让事务 2 等待事务 1,以使事务 2 不会选择与事务 1 相同的“最新”?
【问题讨论】:
-
这里需要使用SERIALIZABLE;你会得到并发错误,这意味着你必须回滚并重试。