【问题标题】:Read uncommitted mvcc database读取未提交的 mvcc 数据库
【发布时间】:2011-08-29 18:37:22
【问题描述】:

假设我想在读取提交模式下(在 postgres 中)执行以下事务。

T1: r(A) -> w(A)
T2: r(A) -> w(A)

如果按此顺序调用的操作:

r1(A)->r2(A)->w1(A)->c1->w2(A)->c2

我预计 T2 必须在 r(A) 处等待。因为 T1 在第一次读取时会为 A 设置一个排他锁,因为它想稍后再写入。但是使用 MVCC 就没有读锁了吗?

现在我有两个问题:

如果我使用 JDBC 读取一些数据,然后执行一个单独的命令来插入读取的数据。数据库如何知道它只在读取时必须进行排他锁?据我所知,在 2PL 中不允许将读锁增加到写锁。

我认为我的假设是错误的......这种情况在哪里等待或一个事务被杀死?未提交的读取不应该允许丢失更新,但我看不出这是如何工作的。

如果有人可以帮助我,我会很高兴。谢谢

【问题讨论】:

    标签: database postgresql transactions mvcc


    【解决方案1】:

    “但是使用 MVCC 没有读锁?”

    MVCC 是一个不同的野兽。 MVCC 中没有“锁”,因为在这种情况下,系统会维护并发运行的事务可能需要的单个行的多个版本。行的“以前的内容”不会“因更新而丢失”(即物理覆盖和破坏),因此确保读者不会看到“新更新”,通过“重定向”读者的查询来解决“以前的内容”,未锁定(因此称为“快照隔离”)。请注意,MVCC 原则上不能应用于更新事务。

    “如果我使用JDBC读取一些数据,然后执行单独的命令插入读取的数据。数据库如何知道它在只读时必须做一个排他锁?增加一个读锁到一个写据我所知,2PL 中不允许锁。”

    你对 2PL 的看法是错误的。 2PL 意味着获取的锁在提交之前永远不会释放。这并不意味着无法加强现有的锁。顺便说一句:这就是为什么诸如“游标稳定性”之类的隔离级别不是 2PL 的原因:它们确实会在提交时间之前释放读锁。

    【讨论】:

    • strict 2PL 实际上不允许提升锁。否则另一个事务可以读取原始数据,然后第一个事务提升为写锁,然后在写入后提交。现在事务 2 写入并提交。这使得使用事务 1 的更新丢失。如果它立即请求写锁,事务 2 将不得不等待。
    • 但现在我了解了 MVCC 或快照隔离。写集必须是分离的。所以随着你写你读到的一切都很好。
    【解决方案2】:

    我预计 T2 必须在 r(A) 处等待。因为 T1 在第一次读取时会为 A 设置一个排他锁,因为它想稍后再写入。但是使用 MVCC 就没有读锁了吗?

    如果您在选择语句中指定for update,则会出现写锁。在这种情况下,如果 r2(A) 尝试锁定与 r1(A) 相同的行,它会等待读取。

    http://www.postgresql.org/docs/9.0/interactive/explicit-locking.html

    如果两个事务开始和结束请求对方已经锁定的行,就会发生死锁:

    r11(A) -> r22(A) -> r12(A) (same as r22) vs r21(A) (same as r11) -> deadlock
    

    【讨论】:

      【解决方案3】:

      PostgreSQL 中的默认事务模式是 READ COMMITTED,但是 READ COMMITTED提供您正在寻找的序列化级别。

      您正在寻找 SERIALIZABLE 事务级别。在阅读 PostgreSQL 关于Transaction Serialization Levels 的文档后查看SET TRANSACTION 命令,特别是SERIALIZABLE mode。 PostgreSQL 的MVCC docs 也值得一读。

      干杯。

      【讨论】:

      • 谢谢,你能解释一下 read commited 会对这些事务做什么吗?我虽然已提交读取,但丢失更新是不可能的?
      • 不,他们很有可能。我讨厌说 RTFM,但我无法比文档更好地解释它。 postgresql.org/docs/9.0/static/…一定要阅读13.2.1的最后两段。
      • 您可能还想查看 PostgreSQL 9.1(现在是 beta1),它添加了真正的可序列化事务隔离级别。
      • 只要我写所有我读到的快照隔离就可以了。当事务的写入集不相交时,将丢弃一个。
      猜你喜欢
      • 1970-01-01
      • 2018-02-14
      • 1970-01-01
      • 1970-01-01
      • 2020-05-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 2019-06-18
      相关资源
      最近更新 更多