【问题标题】:Try to understand MVCC尝试了解 MVCC
【发布时间】:2020-01-04 21:05:00
【问题描述】:

我正在尝试了解 MVCC,但无法理解。例如。 Transaction1 (T1) 尝试读取一些数据行。在同一时间 T2 更新同一行。

交易的流程是

T1 开始 -> T2 开始 -> T2 提交 -> T1 提交

所以第一个事务获取它的数据库快照并返回用户结果,他将在该结果上构建其他计算。但据我了解,客户获得旧数据价值?据我了解 MVCC,在 T1 事务开始后,该事务不知道其他一些事务更改数据。因此,如果现在用户在那之后进行一些计算(不涉及数据库),他是在对错误的数据进行计算吗?或者我错了,第一笔交易有一些机制可以知道该行已更改?

现在让我们更改交易流程。

T2beg -> T1beg -> T2com -> T1com

在 2PL 中,用户获取更新版本的数据是因为锁(T1 必须等待排他锁释放)。但在 MVCC 的情况下,它仍然是旧数据,因为我了解 postgresql MVCC 模型。所以我可以用过时的数据来换取速度。我对吗?还是我错过了什么?

谢谢

【问题讨论】:

    标签: postgresql mvcc


    【解决方案1】:

    是的,您可能会从数据库中读取一些旧数据(并发事务已修改),基于此执行计算并将“过时”数据存储在数据库中。

    这不是问题,因为不是事务发生的实际顺序,而是逻辑顺序更相关:

    如果T1读取一些数据,然后T2修改数据,然后T1根据读取的内容修改数据库,可以说T1逻辑上发生在T2之前,没有不一致。

    只有当 T1 和 T2 修改相同的数据时才会出现异常:T1 读取数据,T2 修改数据,然后 T1 根据读取的内容修改相同的数据。这种异常被称为“丢失更新”。

    只有在最弱(默认)隔离级别READ COMMITTED 下才会发生丢失更新。

    如果您想更好地隔离并发活动,则至少需要使用REPEATABLE READ 隔离。然后 T1 在尝试更新数据时会收到 序列化错误,您将不得不重复该事务。在第二次尝试时,它将读取新数据,并且一切都将保持一致。

    【讨论】:

    • 谢谢。还有一个小问题。我可以在某处阅读隔离级别如何在内部共同工作吗?一些概念?
    • 那将是 SQL 标准。花费几百美元,几乎不可能阅读。如果你想知道它是如何在 PostgreSQL 中实现的,你必须阅读(有据可查的)源代码。一个起点可能是src/backend/access/transam/README
    【解决方案2】:

    事务的流程是下一个 T1 开始 -> T2 开始 -> T2 提交 -> T1 提交。因此,第一个事务获取数据库的快照并返回用户结果,他将在该结果上构建其他计算。但据我了解,客户获得旧数据价值?

    除非 T1 和 T2 尝试更新同一行,否则这通常可以重新排序为:T1 begin; T1 提交; T2开始; T2 提交;

    换句话说,T2 在 T1 做出决定时更改数据可能会实现的任何不良业务结果,也可能在 T1 做出相同决定后立即通过 T2 更改数据而发生。

    【讨论】:

      【解决方案3】:

      事务 1 读取数据时,会将该数据的读取时间戳记到事务 1。

      如果事务 2 尝试读取相同的数据,它会检查数据的读取时间戳,如果数据的读取时间戳小于事务 2,则事务 2 中止,因为 1

      在提交时,我们还会检查数据的读取时间戳是否小于提交事务。如果是,我们中止事务并使用新的事务 ID 重新开始。

      我实际上已经用 Java 实现了 MVCC。 (见transactionrunnermvcc代码)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-22
        • 2011-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-23
        相关资源
        最近更新 更多