基于多个旧值版本的并发控制即MVCC,就是实现一致读
PostgreSQL为每一个事务分配一个递增的、类型为int32的整数作为唯一的事务ID,即xid。 创建一个新的快照时,将收集当前正在执行的事务id和已提交的最大事务id。 根据快照提供的信息,PostgreSQL可以确定事务的操作是否对执行语句是可见的。 PostgreSQL还在系统里的每一行记录上都存储了事务相关的信息,同样用来判断一行记录对于当前事务是否可见。
在PostgreSQL的内部数据结构中,每个元组(行记录)有4个事务可见性相关的隐藏列:xmin , xmax, cmin, cmax 其中cmin和cmax分别是插入和删除该元组的命令在事务对其他事务的可见性相关;xmin保存了创建该行数据的事务的xid,xmax保存的是删除改行的xid。
sarah=# create table tbl_mvcc(id serial primary key, ival int); CREATE TABLE sarah=# insert into tbl_mvcc(ival) values(1); INSERT 0 1 sarah=# select xmin, xmax, cmin, cmax, id, ival from tbl_mvcc where id=1; xmin | xmax | cmin | cmax | id | ival ------+------+------+------+----+------ 599 | 0 | 0 | 0 | 1 | 1 (1 row)
当插入一行数据时,PostgreSQL会将插入这行数据的事务的xid存储在xmin中。 由回滚的事务或未提交的事务创建的行对于任何其他事务都是不可见的;
sarah=# begin; BEGIN sarah=# select txid_current(); txid_current -------------- 622 (1 row) sarah=# insert into tbl_mvcc(id, ival) values(6,6); INSERT 0 1 sarah=# select xmin, xmax, cmin, cmax, id, ival from tbl_mvcc where id=6; xmin | xmax | cmin | cmax | id | ival ------+------+------+------+----+------ 622 | 0 | 0 | 0 | 6 | 6 (1 row)
开启另一个会话:
postgres=# select txid_current(); txid_current -------------- 623 (1 row) sarah=# select * from tbl_mvcc where id=6; id | ival ----+------ (0 rows)
未提交就看不见;
通过xmax值判断事务的更新操作和删除操作:
- 如果没有设置xmax值,该事务对于其他事务总是可见的;
- 如果他被设置为回滚事务xid,该事务对其他事务也是可见的;
- 如果它被设置为一个正在运行,没有commit和rollback的事务xid,该行对其他事务时可见的;
- 如果它被设置为一个已提交的事务xid,该行对这个已提交之后发起的所有事务都是不可见的;
