mysql是怎样运行的-从根儿上理解mysql学习笔记(四)

说明

本文是《MySQL是怎样运行的-从根儿上理解MySQL》的学习笔记,文中的图全部来自于这本书,强烈建议买一本看看,对MySQL理解会特别深入,非常感谢作者"小孩子4919"。

第十八章 事务

事务的四大特性

  • 原子性
    事务中的操作要么全部执行成功,要么失败全部回滚.
  • 一致性
    事务需满足一定的约束
  • 隔离性
    两个事务在执行过程中互不干扰
  • 永久性
    一旦事务执行成功,对数据库的影响是永久的

事务的状态转换

在这里插入图片描述

图18-3 事务的状态转换图

第二十一章 事务的隔离级别和MVCC

事务并发执行时遇到的一致性问题

  • 脏读
    一个事务读取到了另一个未提交事务修改的数据,意味着发生了脏读.

  • 不可重复读
    如果一个事务修改了另一个未提交事务读取的数据,就意味着发生了不可重复读.

  • 幻读
    如果一个事务先根据某些搜索条件查询出一些记录,在该事务未提交时,另一个事务写入了一些符合哪些搜索条件的记录,就意味着发生了幻读.

事务的隔离级别

mysql定义了4中隔离级别

表21-1 SQL标准中规定的并发事务执行过程中可能发生的现象
隔离级别脏读不可重复读幻读
READ UNCOMMITTED(读未提交)可能可能可能
READ COMMITTED(读已提交)不可能可能可能
REPEATABLE READ(可重复读)不可能不可能可能
SERIALIZABLE(串行化)不可能不可能不可能

MVCC原理

版本链

对于InnoDB存储引擎的表来说,它的聚簇索引记录中都包含以下两个必要的隐藏列

  • trx_id
    一个事务对某条记录进行修改时,都会把该事务的事务id赋值给trx_id
  • roll_pointer
    每次对某条聚簇索引记录进行改动时,都会把旧的版本写入到undo日志中.这个隐藏列相当于一个指针,通过它可以找到该记录修改前的信息.
CREATE TABLE student(
sno int(10) NOT NULL AUTO_INCREMENT,
sname varchar(100),
age int(4),
PRIMARY KEY (`sno`)
));
INSERT INTO student VALUES(null, 's3', 12);

假设插入之后两个事务id分别为100和200的事务对这条记录进行UPDATE操作,操作流程如图21-3所示.
在这里插入图片描述

图21-3 UPDATE 操作流程
每个事务对一条记录进行每一次改动,都会记录一条undo日志,每条undo日志也有一个roll_pointer指针,通过这个属性可以将这些undo日志串成一个链表,这个链表称为**版本链**.将利用这个记录的版本链来控制并发事务访问相同记录时的行为称为多版本并发控制(Multi-Version Concurrency Control MVCC). 现在,这条记录的版本链如图21-6所示。

在这里插入图片描述

sno=1的记录的版本链

ReadView

对于InnoDB存储引擎来说,可重复读和读已提交都是通过ReadView实现的,下面就来介绍ReadView,它包含以下四个方面的内容

  • m_ids
    生成ReadView时活跃事务的id列表.活跃的事务是指未提交的事务
  • min_trx_id
    生成ReadView时活跃事务id的最小值,也就是m_ids的最小值
  • max_trx_id
    当前系统中应该分配给下一个事务的事务id值
  • creator_trx_id
    生成该ReadView的事务的事务id

事务隔离级别的核心问题是:版本链中那个版本对当前事务是可见的.有了ReadView就可以很方便判断,判断条件如下:

  • 如果被访问记录的trx_id值与ReadView中creator_trx_id相同,说明是当前事务修改的记录,则该版本当前事务可见;
  • 如果被访问记录的trx_id值小于min_trx_id,说明生成ReadView时该记录已经提交,则该版本当前事务可见;
  • 如果被访问记录的trx_id值大于或等于max_trx_id值,说明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本对当前事务不可见;
  • 如果被访问记录的trx_id值介于min_trx_id和max_trx_id之间,则判断trx_id是否在m_ids中,如果在,说明生成该版本事务是活跃事务,对当前事务不可见;如果不在,说明创建ReadView时生成该版本事务已经提价,该版本对当前事务可见.

总结
如果 t r x _ i d > = m a x _ t r x _ i d trx\_id>=max\_trx\_id trx_id>=max_trx_id或者 t r x _ i d > m i n _ t r x _ i d 且 t r x _ i d < = m a x _ t r x _ i d trx\_id>min\_trx\_id 且 trx\_id<=max\_trx\_id trx_id>min_trx_idtrx_id<=max_trx_id,则该版本对当前事务不可见.如果某个版本对当前事务不可见,那么沿着版本链往下找到可见的版本,如果找到最后一条版本链还是不可见,那么该记录对当前事务不可见.
读已提交和可重复读区别在于,读已提交在事务每次SELECT语句时都会生成ReadView,而可重复读只在第一次SELECT时生成,此后不再发生变化.

第二十二章 锁

InnoDB中的锁

行锁

  • 记录锁
    最普通的锁,包括读锁S和写锁X
  • 间隙锁
表22-7 间隙锁示例
snoname
1s1
2s2
3s3
8s4

如果对sno=8的记录加上间隙锁,那么当前事务在未提交前,其他事务无法插入sno列值处于区间 ( 3 , 8 ) (3,8) (3,8)的记录,这就是间隙锁.mysql的间隙锁是为了解决部分幻读问题.

  • 临键锁
    有时候又想锁住某一条记录,又想阻止其他事务在该记录前面插入新记录,就可以对该记录加临键锁.也就是说,临键锁=记录写锁+间隙锁
  • 插入意向锁
    事务在等待加锁生成的锁称为插入意向锁

表锁

  • 表读写锁
    事务可以对整张表加读锁或者写锁.表级别的写锁与记录锁不兼容,表级别的读锁与记录读锁兼容
  • 表级别意向锁
    表级别的写锁与记录锁不兼容,那么在进行表级别加锁时怎么知道每一条记录是否加读写锁,InnoDB规定记录读锁加成功后也会加表级别的意向读锁IS,记录写锁加成功后也会加表级别的意向写锁IX.表级别的IS和表级别的读锁兼容,表级别的写锁和意向锁都不兼容
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值