多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,引入多版本之后,只有写写之间相互阻塞,其他三种操作都可以并行,这样大幅度提高了InnoDB的并发度。
事务的四大特性
原子性(Atomicity)
事务中的所有操作要么全部成功,要么全部失败
一致性(Consistency)
事务必须使数据库从一个一致性状态转变成另一个一致性状态,比如A和B一共有1000块钱,不管事务中两个人之间如何转账,事务结束的时候两个人的钱一共还是1000块。
隔离性(Isolation)
多用户并发访问的时候,事务之间是隔离的,相互之间不影响。
持久性(Durability)
事务一旦提交了,那么对数据库中数据的改变就是永久性的了。
事务的隔离级别
Read uncommitted(读未提交)
如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。所以会产生脏读(读取了其他事务未提交的数据)
Read committed(读提交)
读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。但是会读取到已经提交写事务的数据。
Repeatable read(可重复读取)
可重复读是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,即使第二个事务对数据进行修改,第一个事务两次读到的的数据是一样的。但是会引起幻读(当前读的情况下,同一个事务中的两次范围查询,后一次查询出的数据可能会比前一次查询出来的数据多)。是Innodb存储引擎默认的隔离级别。
Serializable(序列化)
事务严格的顺序执行,性能很低,一般不推荐使用。
当前读: 读取的是数据的最新版本。
快照读: 读取的数据的历史版本。
undolog: 存储着数据的历史版本,以线性表形式存储,是MVCC中核心组成。
readview: 事务进行快照读的时候生成的视图,里面有三个比较重要的信息
redolog: 通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
1、trx_list:当前活跃的事务列表
2、up_limit_id:列表中最小的事务id
3、low_limit_id:尚未分配的一个事务id
数据库表在新增数据的时候会有三个不可见的隐藏字段。
DB_TRX_ID: 最后进行修改的事务id
DB_ROW_ID: 隐藏主键
DB_ROLL_PTR: 回滚指针(和undolog配合完成数据回滚)
实例说明:
事务1 | 事务2 | 事务3 | 事务4 |
---|---|---|---|
开启 | 开启 | 开启 | 开启 |
update;commit; | |||
快照读 |
四个事务同时开启,然后事务四更新,然后提交。查看事务3是否能读到事务4中的已经提交的数据
trx_list:[1,2,3]
up_limit_id:1
low_limit_id:5
DB_TRX_ID:4
可见性算法: 1、首先比较DB_TRX_ID < up_limit_id,如果小于的话,则当前事务能看到DB_TRX_ID 所在的记录,如过大于等于则进入第二步判断。2、判断DB_TRX_ID >=low_limit_id,如果大于说明DB_TRX_ID 所在的记录是在readview之后才出现的,那么对于当前事务来说一定不可见,如果小于则进入下一步判断。3、判断DB_TRX_ID 是否在活跃事务中,如果在则说明readview生成时刻,事务还是活跃状态,还没有commit,修改的数据当前事务还是看不到,如果不在,则说明这个事务在readview生成之前就已经commit了那么修改的结果是能够看见的。
总结: 可见性算法是相同的,但是在RC隔离级别下是可见的,但是在RR隔离级别下是不可见的,算法中比较的是DB_TRX_ID 和readview中三个属性的关系,那么由此可见,RC和RR两个隔离级别在readview生成的时机是不同的。RC下每次在进行快照读的时候,每次都会生成新的readview,而在RR下只会在第一次快照读的时候会生成readview,之后的快照读操作都会使用第一次生成的readview。
扩展: 数据在更新的时候会先使用logbuffer,logbuffer存在于内存中,是易丢失的,然后会将缓存中的数据写到日志中,然后MySQL会通过日志将数据覆盖到对应磁盘中进行数据覆盖,所以只要日志保存成功了,那么数据就不会丢失。binlog 是MySQL中的日志,而redolog 是innodb的日志,属于不同的组件,为了保证数据的一致性,要保证两种日志保持一致,所以就有了二阶段提交的概念。
二阶段提交流程图:
RR并没有阶段幻读的问题,产生幻读通常是因为使用了当前读,或者在事务中使用快照读的同时,也使用了当前读,导致视图改变,幻读的情况都会产生,而RR最后是通过间隙锁的方式解决这个问题。MySQL中锁的相关概念后续详细梳理。