自增锁是一个表级别锁,那为什么会话A事务还没结束,事务会话B可以执行插入成功呢?不是应该锁表嘛?
这是因为在参数innodb_autoinc_lock_mode
上,这个参数设置为1
的时候,相当于将这种auto_inc lock
弱化为了一个更轻量级的互斥自增长机制去实现,官方称之为mutex
。
不同事务RR和RC下加锁的规则
- 在RC(读已提交) 的隔离级别下 , 对查询条件是主键id的场景 , 会加一个排他锁(X锁) , 或者说加一个X型的记录锁 。
- 在RC(读已提交) 的隔离级别下 , 对查询条件是唯一索引的场景 , 该SQL需要加两个
X
锁,一个对应于 唯一索引上的记录,另一把锁对应于聚簇索引上(主键索引) 。
如果并发的一个SQL,是通过主键索引来,此时 , 如果delete语句没有将主键索引上的记录加锁,那么并发的update就会感知不到delete语句的存在,违背了同一记录上的更新/删除需要串行执行的约束 。
3. 在RC(读已提交) 的隔离级别下,对查询条件是普通索引的场景,那么对应的所有满足SQL查询条件的记录,都会加上锁 。同时,这些记录对应主键索引,也会上锁
4. 在RC(读已提交) 的隔离级别下,对查询条件是无索引(只是一个常规的列)的场景,MySQL会走聚簇索引进行全表扫描过滤 。每条记录都会加上X锁 。但是,为了效率考虑,MySQL在这方面进行了改进,在扫描过程中,若记录不满足过滤条件,会进行解锁操作
5. 在RR(可重复读)的隔离级别下,对查询条件是主键id的场景 , 会加一个排他锁(X锁),或者说加一个X型的记录锁 。和RC是一样的
6. 在RR(可重复读)的隔离级别下 , 对查询条件是唯一索引的场景,该SQL需要加两个
X
锁,一个对应于 唯一索引上的记录,另一把锁对应于聚簇索引上(主键索引) 。和RC是一样的7. 在RR(可重复读)的隔离级别下,对查询条件是普通索引的场景 , 除了会加
X
锁 , 还会加间隙Gap
锁 。Gap锁的提出,是为了解决幻读问题引入的,它是一种加在两个索引之间的锁 。8. 在RR(可重复读)的隔离级别下,对查询条件是无索引的场景,查询条件列没有索引,主键索引的所有记录,都将加上
X锁
,每条记录间也都加上间隙Gap锁
。任何加锁并发的SQL,都是不能执行的,全表都是锁死的状态 。RR隔离级别下加锁规则两个
原则
、两个优化
和一个bug
- 原则1:加锁的基本单位都是
next-key lock
。next-key lock(临键锁)
是前开后闭区间 。 - 原则2:查找过程中访问到的对象才会加锁 。
- 优化1:索引上的等值查询,给唯一索引加锁的时候,
next-key lock
退化为行锁(Record lock)
。 - 优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,
next-key lock
退化为间隙锁(Gap lock) 。 - 一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止 。
总结
- 如果查询没有命中索引,则退化为表锁;
- 如果等值查询唯一索引且命中唯一一条记录 , 则退化为行锁;
- 如果等值查询唯一索引且没有命中记录,则退化为临近结点的间隙锁;
- 如果等值查询非唯一索引且没有命中记录,退化为临近结点的间隙锁(包括结点也被锁定);如果命中记录,则锁定所有命中行的临键锁,并同时锁定最大记录行下一个区间的间隙锁 。
- 如果范围查询唯一索引或查询非唯一索引且命中记录,则锁定所有命中行的临键锁 ,并同时锁定最大记录行下一个区间的间隙锁 。
- 如果范围查询索引且没有命中记录,退化为临近结点的间隙锁(包括结点也被锁定) 。
有没有可能,进一步提高并发呢?
即使写任务没有完成,其他读任务也可能并发,这就引出了数据多版本 。
数据多版本是一种能够进一步提高并发的方法,它的核心原理是:
(1)写任务发生时,将数据克隆一份,以版本号区分;
(2)写任务操作新克隆的数据,直至提交;
推荐阅读
- 引擎之旅 Chapter.4 日志系统
- 金文奎 金文奎
- 关于HM NISEDIT在新版系统下编译并运行提示权限不足问题的解决方案
- SR寄存器BP[x:0]位 痞子衡嵌入式:一个关于Segger J-Flash在Micron Flash固定区域下载校验失败的故事
- SQL的事务
- 面试突击87:说一下 Spring 事务传播机制?
- 一文搞定 Spring事务
- 魅族watch发布时间_魅族watch什么时候发布
- 关于男子登山遇地震:尿里加奶粉求生的信息
- r7 5800h和i7 11800h哪个好_r7 5800h和i7 11800h对比