概念
什么是MVCC ?
MVCC是来处理并发的问题,提高并发的访问效率,读不阻塞写。
为什么需要MVCC?
数据库在并发操作下,如果数据正在写,而用户又正在读,可能会出现数据不一致的问题。比如一行数据只写入了前半部分,后半部分还没有写入,而此时用户读取这行数据时就会出现前半部分是新数据、后半部分是旧数据的现象,造成前后数据不一致。解决这个问题最简单的方法就是加读写锁,写的时候不允许读,读的时候不允许写,不过这样大大降低了数据库的并发性能,此时便引入了MVCC的概念,它的目的便是实现读写事务互不阻塞,从而提高数据库的并发性能。
事务ACID
A 原子性
C 一致性
I 隔离性
D 持久性
高并发的场景下的问题
脏读
不可重复读
幻读
不可重复读的重点是修改:
同样的条件, 你读取过的数据, 再次读取出来发现值不一样了。
幻读的重点在于新增或者删除。
同样的条件, 第1次和第2次读出来的记录数不一样。
当然, 从总的结果来看, 似乎两者都表现为两次读取的结果不一致。
但如果你从控制的角度来看, 两者的区别就比较大。
对于前者, 只需要锁住满足条件的记录。
对于后者, 要锁住满足条件及其相近的记录。
事物隔离级别
1.RU读未提交 脏读/不可重复读/幻读 。不适用MVCC读,可以读到其他事务修改甚至未提交的。
2.RC读已提交 不可重复读/幻读 。其他事务对数据库的修改,只要已经提交,其修改的结果就是可见的,与这两个事务开始的先后顺序无关,不完全适用于MVCC读。
3.RR可重复读 幻读 。完全适用MVCC,只能读取在它开始之前已经提交的事务对数据库的修改,在它开始以后,所有其他事务对数据库的修改对它来说均不可见。
4.S串行化 完全不适合适用MVCC,这样所有的query都会加锁,再它之后的事务都要等待。
隐藏字段说明
事务id
在PostgeSQL中,每个事务都存在一个唯一的id,也称为xid,可通过txid_current()函数获取当前的事务id
tuple
每一行数据,称为一行元组,一个tuple
ctid
tuple中的隐藏字段,代表tuple的物理位置
xmin
tuple中的隐藏字段,在创建一个tuple时,记录此值为当前的事务id
xmax
tuple中的隐藏字段,默认为0,在删除tuple时,记录此值为当前的事务id
cmin/cmax
tuple中的隐藏字段,标识同一个事务中多个语句的顺序,从0开始
实验
要设置一个事务的事务隔离级别,使用SET TRANSACTION命令。
Session 1
postgres=# SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET
设置串行化的事务隔离级别
Session 2
postgres=# SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET
设置串行化的事务隔离级别
postgres=# create table test(id int);
CREATE TABLE
postgres=# insert into test(id) values(1);
INSERT 0 1
postgres=# insert into test(id) values(2);
INSERT 0 1
postgres=# insert into test(id) values(3);
INSERT 0 1
Session 1
postgres=# SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET
设置串行化的事务隔离级别
Session 2
postgres=# SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET
设置串行化的事务隔离级别
Session 1
postgres=# BEGIN;
BEGIN
postgres=# update test set id=11 where id=1;
UPDATE 1
Session 2
postgres=# begin;
BEGIN
postgres=# update test set id=1 where id=1;
阻塞状态
Session 1
postgres=# ROLLBACK;
ROLLBACK
Session 2
提示以下信息
ERROR: could not serialize access due to concurrent update
参考
https://www.postgresql.org/docs/13/transaction-iso.html