0

我想知道当两个事务SELECT ... FOR UPDATE并行执行查询时会发生什么。背景是我想使用SELECT ... FOR UPDATEwith实现一个作业队列SKIP LOCKED,如下所示:https ://vladmihalcea.com/database-job-queue-skip-locked/ 。但在本文中,查询非常简单。

具有两个事务 T1 和 T2 的示例(事务隔离级别设置为READ_COMMITTED):

  1. T1 开始
  2. T1 执行SELECT ... FOR UPDATE,搜索新行,这需要一些时间。
  3. T2开始
  4. T2SELECT ... FOR UPDATE使用与 T1 相同的 WHERE 子句和参数执行,这也需要一些时间。
  5. T1 终于找到所有行,锁定它们
  6. T1 开始更新行(例如,通过将它们标记为现在为 IN_PROGRESS)
  7. T2 终于找到行 => 现在会发生什么?

一些问题:

  1. 我假设 T1 将行锁定在原子操作中。这个对吗?
  2. 那么当 T2 最终找到它的结果集并尝试锁定它无法做到的行时?在这种情况下,T2 如何反应?我的假设是它会等到 T1 释放锁(当不使用 NOWAIT 时)。
  3. 如果 T2 在 T1 进行任何更改(例如将作业状态从 NEW 更改为 IN_PROGRESS)之前完成查询怎么办?两个事务可以找到相同的结果集吗?
  4. 如果 T1 以某种方式标记锁定的行(例如,通过将状态列从 NEW 更改为 IN_PROGRESS)并且 T2 查找原始状态(NEW),那么 T2 是否会SKIP LOCKED跳过标记的行?在 T1 进行更改后,T2 会重新评估它的结果集吗?
4

1 回答 1

2
  1. 每个事务在找到行时都会锁定它们,因此锁定不是原子的。T1 可能会锁定几行,而 T2 会锁定其他一些行。

  2. 由于每个事务在找到行时会立即锁定行,因此不会发生这种情况。行被锁定,在这种情况下它被跳过,或者它没有被锁定,在这种情况下它被锁定。

  3. 如果 T1 在 T2 完成扫描表之前提交,T2 将愉快地锁定所有已由 T1 处理的行。

  4. 是的,这会奏效。T2 将在检查条件并锁定行之前获取每行的最新版本。

于 2021-04-20T15:15:02.820 回答