根据我的理解,postgres 使用两个额外的字段 Xmin 和 Xmax 来实现 mvcc,假设我们有 Employee 表,其中包含 id 和 name 列。
下面是一些 crud 操作以及它们如何同时工作(考虑隔离级别 = READ_COMMITTED),问题是何时何地获取实际锁。
- 插入-> 新事务插入一条新记录,该记录在提交之前对其他事务不可见,因此在这种情况下没有问题,也不需要锁定或版本控制。假设 id = 1,name = "aa" 被插入。Postgres 为 mvcc Xmin = current txn id(假设为 100)和 Xmax = 0/null 添加了 2 个额外的列。
id | name | Xmin | Xmax
------------------------------
1 | aa | 100 | null
使用并发读取更新-
一个)。一个新事务开始将名称更新为“bb”(对于 id = 1)。同时还有另一个事务开始读取相同的数据。
乙)。使用 Xmin = 当前事务 id(假设为 200)和 Xmax = null 以及 id = 1、name = bb 创建一个新的元组(postgres 中的不可变对象表示一行)。旧版本的 id = 1 也被更新为 Xmax = 200。读取事务看到旧版本的数据 Xmin = 100 并返回。 在这种情况下是否需要任何锁定?我认为没有,但它可能会更新旧元组的 Xmax。
以下是多个版本的相同记录(仅用于解释目的),最新版本的 Xmax = null。
id | name | Xmin | Xmax
------------------------------
1 | aa | 100 | 200
1 | bb | 200 | null
使用并发更新进行更新-
一个)。交易(txn id = 300)开始将 id = 1 更新为 name = cc。另一个事务(txn id = 400)开始将同一记录(id = 1)更新为name = dd。如果这种情况也通过创建新元组并标记旧元组的 Xmax 以同样的方式进行,那么我认为它会产生问题,因为 300 和 400 都会创建一个新元组并标记旧元组的 Xmax = txn id。在这种情况下,更新可能会丢失。
在这种情况下,排他锁是由第一个 txn 获取的,其他并发更新 txns 会等到任何正在进行的 txn 完成,或者 postgres 有其他方式处理它吗?