一、隔离性的定义
隔离性指多个事务间具有隔离,同时进行互不影响。 -- 在解决并发读写的问题
二、并发读写数据库存在的问题
1、脏读:A事务读到了B事务没有提交的数据(这条数据可能被回滚,导致A事务跟着出错)。
2、不可重复读:A事务第一次读取某条数据后,B事务对该数据做了修改,A事务再去读这条数据的时候发现跟上次读取的结果不一样。
3、幻读:A事务读取某范围内的数据并做了修改,此时B事务在这个范围内增加了新数据,A事务再去读取该范围内数据时发现某些数据没有被修改(好像出现幻觉,需要通过间隙锁去解决)。
三、前置知识点
undolog : 事务支持回滚操作,那么必须有回滚机制。mysql基于版本链做回滚,具体实现方法如下。
1、在每条记录中包含一个回滚指针指向上一个版本在undolog中的地址,包含创建这条记录的事务id。
2、每次对数据做操作的时候,都会生成一条反向的sql语句(执行后数据会回到操作前的版本)存入undolog中,新创建的数据的回滚指针会指向对应undolog的地址。
3、在需要回滚时,通过回滚指针找到对应的回滚sql语句去指向。
四、ReadView和可见性算法
ReadView 中包含的信息为 :
m_ids:生成ReadView的这一刻系统中活跃的事务的事务id列表。 --》事务2、4、5
min_trx_id:m_ids中的最小值。 --》 事务2
max_trx_id:当前系统应该分配给下一个事务的id(不是m_ids中最大的)。 --》 事务7
creator_trx_id:生成该ReadView的事务id。 --》 事务6
可见性算法如下:
1、先比较当前记录中的事务id是否小于ReadView中的最小事务id,如果小于则说明当前事务能看到这条记录。 --》 比如说事务1
2、再判断记录中的id是否大于等于尚未分配的事务id,如果大于等于,则说明这条记录是ReadView创建之后的事务生成的,那么当前事务肯定不可见。 --》 比如说事务7、8
3、再判断记录中的事务id是否在ReadView活跃的事务列表中,如果在则说明我生成ReadView的时候这条数据被其他事务创建了但是还没被提交,当前事务不可见。 --》 比如说事务2、4、5
4、如果不在,则说明这条记录在ReadView生成前就提交了,当前事务可见。 --》 比如说事务3
总结起来就是以ReadView为分界线,只有产生ReadView前提交的事务做出的修改可以被当前事务看见。事务在读一条数据的时候,最开始读到的都是数据库中的记录, 里面包含修改他的事务的id(DB_TRX_ID)和回滚指针(DB_ROLL_PTR )。事务通过自己的ReadView和可见性算法来判断当前读到的这条数据是否可见, 如果不可见再通过归滚指针去找上一个版本。如果还是不可见则继续找上一个版本,找到最新的一条符合条件的记录或者nill。
五、四大隔离级别
读未提交:一个事务直接读取其他事务未提交的数据(直接读数据库中最新的版本,不需要经过undolog)。 -- 存在脏读、不可重复读、幻读
读已提交:一个事务【每次select】的时候都会【生成新的ReadView】,根据可见性算法读其他事务已提交的数据。 -- 存在不可重复读(每次ReadView都要重新生成)、幻读
可重复读:一个事务在【第一次select】数据的时候【才生成ReadView】,后面每次select都是根据这个ReadView去执行可见性算法读其他事务已提交的数据。 -- 存在幻读
串行化: 一个事务中的所有sql语句是一个不间断的整体,一次性执行完这个事务中所有sql语句后才开始执行下一个事务中的sql语句(用锁避免并发,效率低)。