SELECT 是否防止返回的行被删除?

Does SELECT prevent returned rows from getting deleted?

假设我有:

  1. T1: SELECT id FROM x WHERE timestamp < y (returns id = [1, 2, 3])
  2. T2:DELETE FROM x WHERE id = 1
  3. T1:SELECT timestamp, value FROM x WHERE id = 1

具有 READ-COMMITTED 隔离。

第 3 步 运行 是否存在返回空结果的风险,或者第 1 步是否获得某种 lock/snapshot 以防止第 2 步更改结果? (我假设 REPEATABLE-READ 会做我想做的事,但这个问题是关于 READ-COMMITTED 的)。

我正在使用 postgresql,但我对独立于数据库的答案感兴趣。例如,如果某些数据库阻止删除而其他数据库不阻止删除,我想知道这一点。谢谢。

PostgreSQL 案例:

在 PostgreSQL 中,读取一行不会获取阻止该行被并发删除的锁:

  • 如果 T2 在第 3 步之前提交,T1 将看到它的结果并且 return 一个空结果集。

  • 如果步骤 3 在 T2 提交之前运行,则 T2 的结果尚不可见,查询将 return 匹配行。

一般情况:

数据库系统有不同的方式来提供事务隔离,行为会根据所使用的方法而有所不同。

  • 一些数据库系统,如 DB2 或 Microsoft SQL Server,会在读取行时锁定行以防止并发更新。

    在此类数据库系统上,DELETE 将阻塞,并且该行在步骤 3 中可见。

  • 大多数数据库系统使用某种multi-versioning,即它们保留旧版本的行,而修改行的事务是进行中。

    在这样的数据库系统上,DELETE 不会被阻塞,步骤 3 的结果将取决于 T2 是否已经提交。

解决方法:

如果您正在寻找使所有数据库系统的行为具有确定性的解决方案,您可以使用更高的隔离级别,或者您可以通过指定 悲观锁定 FOR UPDATE 在步骤 1 的 SELECT 语句中。然后步骤 2 将始终阻塞。