事务的四个特性ACID
- 原子性
- 一致性
- 隔离性
- 持久性
MVCC:多版本并发控制,解决数据并发读写问题
MVCC多版本并发控制指的是维持一个数据的多个版本,使得读写操作没有冲突。快照读是mysql为了实现MVCC的一个非阻塞读功能。
MVCC实现原理:
一行数据后面会有隐藏字段。
- DB_TRX_ID(最近修改事务ID,记录创建当前记录或者最后一个修改的事务ID)
- DB_ROLL_PTR(回滚指针,指向这条记录的上一个版本)
- DB_ROW_ID(隐藏主键)
一行数据的字段:
undolog:
回滚日志,实际记录的是之前数据行的历史版本。是一个逻辑日志。
undolog的生成过程:
在事务对某一行数据进行修改后,就要将之前的数据行记录到undo日志中。
undolog会形成一个链表,链首存储的是最新的旧纪录,而链尾放的是最旧的旧日志。
undolog不会无限膨胀下去,会存在要给prege线程,当发现当前记录不需要回滚,或者是不需要参与到MVCC就会将数据进行删除。
readview:
当事务在进行快照读的时候,会生成一个读视图,来进行可见性判断,可见性判断是由可见性算法来确定的
表示其他事务能否读取到本事务的数据
有几个字段:
- trx_list:当前系统活跃的事务ID
- up_limit_id:活跃事务列表中最小的ID值
- low_limit_id:当前系统尚未分配的下一个事务ID
例子:
分析:
参照可见性算法:
这个要先考虑隔离级别,在不同的隔离级别下,会有不同的结果
RC:提交读。 能
RR:可重复读。能
RC:提交读。能
RR:未提交读。不能
分析:
,
即使执行了第二个select对应的也是用的第一个select生成的视图
重点:
能否看到修改的数据,取决于可见性算法,可见性算法比较的时候取决于readview中的结果值
两种情况的差异是因为在不同的隔离级别的时候,生成readview的时机是不同的。
如果是RC隔离级别,每次执行快照读都会生成新的readview
如果是RR隔离级别,只有在当前事务第一次进行快照读对的时候生成readview。之后的快照读操作都会用当亲的readview。
幻读问题的解决是因为间隙锁,而不是因为MVCC,MVCC可能会导致幻读
幻读就是两次读出来的数据行总数不同。
出现幻读问题
出现了三条记录。
结论:
如果当前的所有操作都是当前读,那么是不会产生幻读问题,只有当前读和快照读一起使用的时候才会产生幻读问题
解决办法就是加锁。
加了锁之后。右边数据被阻塞了。
锁的理解:
不同维度来区分
锁的粒度来分
- 行锁
- 表锁
- 页锁
按照读写来分
- 共享锁(读锁)
- 排它锁(写锁)
实际是否加锁来分:
- 乐观锁不加锁
- 悲观锁加锁
意向锁是属于表锁的一类:
- 记录锁
- 间隙锁
- 临建锁