尝试理解 MVCC

Try to understand MVCC

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

交易流量为

T1 begin -> T2 begin -> T2 commit -> T1 commit

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

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

T2beg -> T1beg -> T2com -> T1com

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

谢谢

The flow of transaction is next T1 begin -> T2 begin -> T2 commit -> T1 commit. So the first transaction get it snapshot of database and returns to user result on which he is gonna build other calculation. But as I understand, customer get the old data value?

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

换句话说,在 T1 做出决策时 T2 更改数据可能导致的任何不良业务结果,也可能在 T1 做出相同决策后立即更改数据而导致。

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

这不是问题,因为逻辑顺序比交易发生的实际顺序更重要:

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

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

丢失的更新只能发生在最弱的(默认)隔离级别 READ COMMITTED

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

每个交易只能看到比该交易 ID 更年轻或等于该交易 ID 的数据。

事务1在读取数据时,将那条数据的读取时间戳标记给事务1。

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

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

我们还检查写入时间戳是否小于我们的事务。年轻的交易获胜。

存在一种边缘情况,如果较旧的事务领先于较新的事务,则较新的事务可以中止。

我实际上已经在 Java 中实现了 MVCC。 (参见 transaction, runner and mvcc 代码)