【问题标题】:Does SELECT prevent returned rows from getting deleted?SELECT 是否会阻止返回的行被删除?
【发布时间】:2018-07-26 23:10:37
【问题描述】:

说我有:

  1. T1:SELECT id FROM x WHERE timestamp < y(返回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 步是否会获取某种锁定/快照以防止第 2 步更改结果? (我假设REPEATABLE-READ 会做我想做的事,但这个问题是关于READ-COMMITTED)。

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

【问题讨论】:

  • 确实取决于 DBMS 及其设置。例如,在 SQL Server 中,您可以打开和关闭 SNAPSHOT ISOLATION。在没有具体提示的情况下,步骤 1 中的简单 SELECT 不应阻止 T2 删除该行。 (我假设第 2 步在第 1 步完成后运行,事务 T1 尚未结束的事实并不重要)
  • @VladimirBaranov 谢谢。 REPEATABLE-READ 会阻止 T2 删除该行(或至少将其从我的快照中隐藏),对吗?
  • 抱歉,我对那个隔离级别没有太多经验。 SERIALIZABLE 绝对足够了。不同的 DBMS 实现的隔离级别可能略有不同,因此您最好查看 DBMS 的文档
  • 对于 SQL Server REPEATABLE READ 看起来足够生活。 “指定语句不能读取已被其他事务修改但尚未提交的数据,并且在当前事务完成之前,没有其他事务可以修改当前事务已读取的数据。共享锁被放置在每个读取的所有数据上事务中的语句并一直保留到事务完成。这可以防止其他事务修改当前事务已读取的任何行。" 对于 Postgres,请参阅其文档

标签: sql postgresql database-locking read-committed


【解决方案1】:

PostgreSQL 案例:

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

  • 如果 T2 在步骤 3 之前提交,T1 将看到其结果并返回一个空结果集。

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

一般情况:

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

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

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

  • 大多数数据库系统使用某种多版本,即在修改行的事务正在进行时,它们保留行的旧版本。

    在此类数据库系统上,DELETE 未被阻塞,步骤 3 的结果将取决于 T2 是否已提交。

解决方案:

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

【讨论】:

    猜你喜欢
    • 2014-05-28
    • 2022-01-17
    • 1970-01-01
    • 2015-04-24
    • 2015-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多