文章目录
- 什么是事务?并发事务引发的问题?什么是MVCC?
- 1.事务的四大特性
- 2.并发事务下产生的问题:脏读、不可重复读、幻读
- 3.如何应对并发事务引发的问题?
- 4.什么是MVCC?
- 5.可见性规则?
- 参考资料
什么是事务?并发事务引发的问题?什么是MVCC?
1.事务的四大特性
- 原子性是指事务中的所有操作要么全部执行成功,要么全部执行失败。
- 一致性是指在事务执行前后,数据库的状态必须一致。
- 隔离性是指数据库允许多个并发事务对同一个数据进行读写和修改的能力。
- 持久性是指事务完成后对数据的修改是永久的。
2.并发事务下产生的问题:脏读、不可重复读、幻读
脏读就是指在事务A中已经修改过的数据被事务B读取了,但是这个事务A回滚了,那么事务B就是脏读了。
不可重复读是指事务A多次读取同一个数据,但是其中有一次被事务B修改了,那么就会造成前后不一致,这就是不可重复读。
幻读是指事务A多次查询数据数量,但是在其中某一次可能因为事务B的增删操作,发现不一致时,就是幻读。
按我理解就是说,不可重复读注重的是这个数据是否更新了,而幻读注重的时候是否进行了增删操作导致数据量变了。
3.如何应对并发事务引发的问题?
数据库为我们提供了四大隔离级别:读未提交、读提交、可重复读、串行化。
- 读未提交:事务可以读取其他事务未提交的数据,如果未提交的事务回滚,那么这些数据就是无效的。
- 读提交:事务只能读取其他事务提交的数据。但是在事务A中多次读取同一数据,若其他事务已经提交了对这个数据的修改,就会造成不可重复读问题。
- 可重复读隔离级别:在一个事物执行过程中看到的数据都是这个事务启动时的数据快照,就算是修改了这个数据并提交的事务也不会影响这个数据快照。但是若进行insert和delete操作就会发生幻读现象。
- 串行化:通过加锁机制,确保事务串行执行,避免所有并发问题。
那么这些隔离级别是怎么实现的呢?
对于读未提交隔离级别,什么问题也没有解决,所以直接读取最新的数据即可。
对于读提交和可重复读隔离级别,都是通过MVCC实现的,只是创建的read view时机不同。
对于串行化,通过加读写锁的方式避免并行访问。
4.什么是MVCC?
MVCC是MySQL在创建事务时,读提交和可重复读隔离级别使用的核心控制机制。
MVCC是通过undo日志版本链和read view实现的,每一个事务在创建的时候都会生成一个read view。
m_ids
:当前活跃事务的 ID 列表。
min_trx_id
:m_ids
中的最小事务 ID。
max_trx_id
:下一个即将分配的事务 ID。
creator_trx_id
:创建该 Read View 的事务 ID。
read view有四个字段+行数据中隐藏的两个字段实现了MVCC。行数据中的两个隐藏列实现了undo log版本链,trx_id记录正字啊操作这个行数据的事务,roll_pointer记录上一个历史版本的数据用来回滚操作。
MVCC就是通过trx_id、回滚指针和read view共同实现事务的可见性规则的。
在读提交和可重复读隔离级别下,需要通过MVCC来实现。
读提交是在事务执行过程中,每进行select操作时都会创建一个read view,所以每次select都能看到其他事务最近提交的数据。可重复读是在事务开始执行时创建一个read view并且在之后执行过程中都复用这个read view,那么在查询数据的时候都是事务开始之前的数据。
那么MVCC就是在这两个隔离级别下所使用的核心机制,避免了锁的使用(写操作还是需要加锁的),因为锁的效率更低。
MVCC的实现流程:每个事务都会创建一个read view,并且有唯一一个creator_trx_id,如果这个事务中操作了某些行数据,那么就会将这个creator_trx_id记录到行数据的trx_id中,并且会让行数据的回滚指针指向历史版本,然后这个read view就会统计当前系统中活跃的事务id到m_ids列表中,min_trx_id记录最小的值,max_trx_id记录要创建的事务的下一个id,如果某个事务需要回滚那么就会通过这个creator_trx_id去查找对应的最新的trx_id的行数据,然后遍历回滚指针恢复到最初的数据。
如何去判断这个read view是怎么进行可见性规则的?m_ids就是活跃事务列表,仅存放所有还在活跃的事务。 这个m_ids分为三部分,已经提交的事务,正在活跃的事务区间,但是这个区间内部也有已经提交的事务因为并发,以及待未创建的事务id,如果在第一部分是可以读取的,在第二部分要去进行判断(错误描述)。
那我是不是可以理解为 这个m_ids列表存放的事务id,其实系统中的所有read view的m_ids都是一样的呢?
不是的,m_ids中存放的创建当前read view是系统中活跃的事务id(自身不计入)。
综上,MVCC就是多版本并发控制,通过记录历史版本数据,解决了读写冲突问题,避免了查询数据时加读锁,提高了事务的并发性能。事务在启动时,会创建read view记录当前未提交的事务,通过与历史版本数据的事务id根据可见性规则判断,当前记录是否可见,否则就继续跟进undo log版本链去查早最近的可见数据。
5.可见性规则?
可见性规则是由read view实现的,read view中有四个字段:creator_trx_id、min_trx_id、max_trx_id、m_ids。
如果记录的事务id小于min_trx_id,那么就是可见的。
如果记录的事务id大于等于max_trx_id,就是不可见的。
如果记录的事务id在min_trx_id和max_trx_id之间,还需要判断这个id是否存在于m_ids中,若存在就是未提交,是不可见的,否则就是可见的。
参考资料
1、https://xiaolincoding.com/mysql/transaction/mvcc.html#%E4%BA%8B%E5%8A%A1%E7%9A%84%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E6%9C%89%E5%93%AA%E4%BA%9B