【问题标题】:Why predicate locks cannot be acquired through an explicit locking query syntax为什么无法通过显式锁定查询语法获取谓词锁
【发布时间】:2016-01-06 13:36:34
【问题描述】:

大多数 RDBMS 允许在被选择的行上获取共享独占锁。例如,PostgreSQL 有这样的语法:

SELECT * 
FROM post 
WHERE id=10 
FOR SHARE;

使用 FOR SHARE,即使在 READ_COMMITTED 隔离级别,我们也可以获取共享锁,并且可以在不实际使用 REPEATABLE_READ 事务隔离的情况下防止不可重复读取现象。

但是为了防止幻读,SERIALIZABLE 是唯一的方法。为什么没有明确的锁定语法来获取谓词锁?

据我所知,我不记得在 Oracle、SQL Server、MySQL 或 PostgreSQL 中看到过任何此类结构。

【问题讨论】:

  • FOR SHARE 获得一个读锁,而 FOR UPDATE 给你一个写锁。使用 SERIALIZABLE 时,数据库会在所有检索到的行上获取 SHARED 锁(以防止模糊读取)以及范围/谓词锁(以防止幻读)。
  • 为什么要在每个查询中强制执行事务隔离级别,而不仅仅是使用事务隔离级别?在 Oracle 中,您始终可以对 SCN 使用闪回查询来避免幻读(如果您将事务隔离级别设置为可序列化,这就是 Oracle 在幕后所做的事情)。这不需要任何形式的锁定或任何形式的阻止其他会话。但它与抛出 ORA-08177: Cannot serialize access for this transaction error for non-serializable modify 的行为不同。
  • 鉴于您列出的每个数据库可能会有不同的答案,但是,我认为这个问题要么“过于宽泛”,要么“主要基于意见”。
  • 隔离级别设置在连接级别,从该特定连接启动的所有事务都将继承它。我想到了一个更细粒度的控制,我可以在较低的隔离级别 (READ_COMMITTED) 上使用显式锁定来防止一些异常
  • 它可能被标记为不适合 SO 规则,但我认为原因是普遍的,它与冲突解决检测机制有关。

标签: mysql sql-server oracle postgresql transactions


【解决方案1】:

在 PostreSQL 中,可序列化隔离级别基于所谓的Serializable Snapshot Isolation,它使用谓词锁不是为了实际锁定,而是用于监视可能导致序列化异常的条件。此机制仅在 Serializable 级别有效;没有办法在较低级别使用谓词锁。

但是为了防止幻读,您实际上只需要 PostgreSQL 中的可重复读取隔离级别(尽管 SQL 标准对隔离级别有什么规定)。详情请见the documentation

对于 Oracle,它根本没有谓词锁。其 Serializable 隔离级别使用快照隔离(与 PostgreSQL 中的可重复读取相同),可防止幻读但允许other serialization anomalies

我没有关于 SQL Server 和 MySQL 的信息。

【讨论】:

  • 我投了反对票,因为这并不能真正回答问题。这问为什么 PostgreSQL 中没有通过 SQL 语法明确支持谓词锁。例如,调用select count(*) from cars where color = 'blue' for update 可以创建一种“谓词锁”,它会阻止尝试添加、删除和更新返回集中的行(这就像谓词锁在 SERIALIZABLE 模式下所做的那样)。
  • 它已经对具体的行执行此操作,但它不会在 " 上创建任何与 color = 'blue' 匹配的锁,即使它在执行时不存在或不可见初始查询”。这会很方便,但是其他 DBMS 的经验表明它很容易出现死锁并且很难使其表现良好,因此实际上 Pg 提供了SERIALIZABLE 隔离作为替代方案。您可以执行应用程序级逻辑来模拟谓词锁,使用建议锁定,或使用标记行、唯一约束和行锁定。
【解决方案2】:

标准没有指定谓词锁定,或者必须使用谓词锁定来实现SERIALIZABLE。它只指定了SERIALIZABLE 必须防止的异常情况......而且大多数 DBMS 实际上并没有完全遵守那里。

在 PostgreSQL 的情况下,没有明确的谓词锁定语法,因为没有谓词锁。 PostgreSQL 对SERIALIZABLE 使用更类似于乐观锁定的东西,它跟踪事务间依赖关系,如果检测到循环依赖关系则中止。这不遵循锁的语义,并且明确地执行也不是很有用。

【讨论】:

  • 这对于弱于 SERIALIZABLE 的隔离级别很有用。请参阅我在 Egor 的答案中添加的评论。
猜你喜欢
  • 2017-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-02
  • 2019-06-17
  • 1970-01-01
  • 2021-08-17
  • 2023-04-09
相关资源
最近更新 更多