2

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

交易流程为

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

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

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

T2beg -> T1beg -> T2com -> T1com

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

谢谢

4

3 回答 3

5

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

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

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

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

丢失更新只能发生在最弱(这是默认)隔离级别的情况下,READ COMMITTED.

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

于 2019-09-02T05:33:12.807 回答
0

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

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

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

于 2019-09-01T14:38:27.487 回答
0

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

如果事务 2 尝试读取相同的数据,它会检查数据的读取时间戳,如果数据的读取时间戳小于事务 2,则事务 2 被中止,因为 1 < 2 -- 1 在我们之前到达那里并且他们必须在我们面前完成。

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

我实际上已经用 Java 实现了 MVCC。(参见事务运行程序和mvcc代码)

于 2021-06-22T17:12:52.077 回答