目录
一、事务的四要素(ACID)
二、mysql的事务的隔离级别
三、多版本并发控制(multi-version concurrency control)
3.1 功能
3.2 原理
1. 原子性(atomicity):all done 或者 all not done
2. 一致性(consistency):事务开启和结束之后,数据的完整性没有被破坏
3. 隔离性(isolation):一个事务的执行不能被另一个事务干扰
4. 持久性 (durability):事务一旦提交,对于数据库的变更是永久性的
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(read uncommitted) | ✔️ | ✔️ | ✔️ |
读已提交(read committed) | ❌ | ✔️ | ✔️ |
可重复读(repeatable read) | ❌ | ❌ | ✔️ |
串行化(serializable) | ❌ | ❌ | ❌ |
默认的隔离级别是:可重复读(repeatable read)
脏读:事务A读了事务B更新但未提交的数据,事务B回滚之后,A读到的就是脏数据
不可重复读:事务A需要多次读同一数据,事务B在事务A读数据的过程中,对数据进行了更新,则A多次读同一数据,结果不一致
幻读:事务A读某一个数据,其他事务又执行了插入操作,事务A再次按照同一条件查询时,数据变多了
使得InnoDB在read committed和 repeatable read两种隔离级别下的一致性读有了保障。换句话说,在这两种隔离级别下,每个事物执行普通的select时,查询到的都是已经提交的数据或是当前事务更新的数据。这个技术是一项非常强大的技术,可以使得查询操作不用等待锁释放就能执行。当然这并不是一项通用技术,一些其他的数据库产品以及mysql的其他存储引擎并不支持。
3.2.1 版本链
InnoDB存储引擎会给数据库的每一行增加三个隐藏字段
1. row_id:如果存在主键或是非NULL唯一键,该字段非必须
2. trx_id:事务ID,每次对某一个记录进行更新时,会把更新这条记录的事务ID赋值给隐藏的trx_id字段
3. roll_ptr:每次对某条记录进行修改时,这个隐藏列会存一个指针,可以通过这个指针找到修改之前的数据
3.2.2 ReadView
ReadView中包含4个主要内容:
(1) m_ids:生成当前ReadView时,当前系统中的活跃事务列表
(2)min_trx_id:生成当前ReadView时,当前当前系统中最小的活跃事务Id,即m_ids中的最小值
(3)max_trx_id:生成当前ReadView时,系统应该给下一个事务分配的id值
(4)creator_trx_id:生成当前ReadView的事务Id
注意:max_trx_id并不是m_ids中的最大值,事务ID是递增分配的。
e.g. 比如m_ids中有1,2,3三个活跃事务,之后事务3提交了,那么生成新的ReadView时,m_ids中只有1,2两个事务,而max_trx_id=4
3.2.3 一致性读(consistent read)
对于读已提交和可重复读两种隔离级别,可以借助ReadView,按照如下规则实现一致性读:
(1)如果被访问版本的trx_id与creator_trx_id相同,则表示当前事务正在访问自己修改的版本,该版本数据对当前事务可见;
(2)如果被访问版本的trx_id小于min_trx_id,则表示生成该ReadView时,当前版本的数据已经提交,该版本数据对当前事务可见;
(3)如果被访问版本的trx_id大于max_trx_id,表示生成该ReadView时,该版本的事务还未开启,该版本的数据对当前事务不可见;
(4)如果被访问版本的trx_id大于min_trx_id,小于max_trx_id,就需要判断当前版本的trx_id是否在m_ids中。如果在,则表示当前版本还为提交,该版本数据不可用;如果不在,则表示该版本数据已经提交,该版本数据可以被当前事务访问