根据我的理解,postgres使用两个额外的字段Xmin和Xmax来实现mvcc,假设我们有带有id和name列的Employee表。
下面是一些crud操作以及它们是如何并发工作的(考虑隔离级别= READ_COMMITTED),问题是何时在何处获得实际锁。
id | name | Xmin | Xmax
------------------------------
1 | aa | 100 | null具有并发读取的
a)。一个新的事务开始将名称更新为"bb“(对于id = 1)。同时,还有另一个事务开始读取相同的数据。
b)。一个新的元组( postgres中表示一行的不可变对象)将使用Xmin =当前事务id (假设200)和Xmax = null以及id = 1、name = bb创建。此外,id =1的旧版本也会被更新为具有Xmax = 200。returns看到Xmin = 100的旧版本的数据并返回。在这种情况下是否需要任何锁?我认为不是,但它可能会更新旧元组的Xmax.
下面是多个版本的相同记录(只是为了解释),最新版本具有Xmax = null。
id | name | Xmin | Xmax
------------------------------
1 | aa | 100 | 200
1 | bb | 200 | null具有并发更新的
a)。事务(使用txn id = 300)开始将id =1更新为name = cc。另一个事务(txn id = 400)开始将相同的记录(id = 1)更新为name = dd。如果这个场景通过创建新元组和标记旧元组的Xmax来以同样的方式进行,那么我认为它会产生问题,因为300和400都将创建一个新的元组并标记旧元组的Xmax = txn id。在这种情况下,更新可能会松动。
在这个场景中,排他锁是由第一个txn和其他并发更新txns获得的,等待任何正在进行的txn完成,或者有其他一些处理它的方式?。
发布于 2020-07-29 16:40:22
插入->新事务插入一个新记录,在其他事务提交之前它是不可见的,因此在这种情况下不存在任何问题,也不需要锁或版本控制。
这不是真的。插入的元组在插入时被锁定。例如,如果有一个唯一的约束,而其他人试图插入一个冲突的元组,这就很重要了。
使用并发
进行Read....Is更新--在本例中需要任何锁
当xmax正在更新时,在保存元组的缓冲区上有一个“轻量级”锁,该锁将在字段更新后立即释放(在事务期间不保持)。这个轻量级锁包括一个屏障,以确保任何其他进程都会看到更改,而不是看到过时的缓存版本。
读取器将看到xmax为0并返回元组,或者看到xmax为200并看到200尚未提交,并且返回元组,因为它知道xmax = 200表示的锁不适用于它,这仅仅是读取器。
更新与并发更新..。
将其id写入即将过时的元组的xmax的第一个进程将获胜。第二个将在xmax中看到其他人的有效id,并阻塞直到其他事务提交或回滚,然后决定要做什么。由于存放元组的缓冲区上的锁很轻,所以它们都不能在没有注意到彼此更改的情况下更新xmax。
https://stackoverflow.com/questions/63149069
复制相似问题