Ⅰ、总览

  • S行级共享锁

    lock in share mode
  • X行级排它锁

    增删改
  • IS意向共享锁
  • IX意向排他锁
  • AI自增锁

Ⅱ、锁之间的兼容性

X IX S IS
X × × × ×
IX × ×
S × ×
IS ×

2.1 意向锁

意向锁揭示了下一层级请求的锁类型,意向锁全兼容

  • IS:事务想要获得一张表中某几行的共享锁
  • IX:事务想要获得一张表中某几行的排它锁

InnoDB存储引擎中意向锁都是表锁,是不是读下来很懵逼?

如果没有意向锁,当你去锁一张表的时候,你就需要对表下的所有记录都进行加锁操作,且对其他事务刚刚插入的记录(游标已经扫过的范围)就没法在上面加锁了,此时就没有实现锁表的功能

对一棵树加锁的概念:

从上往下的,先加意向锁再加记录锁,内存操作,很快,释放操作则是从记录锁开始从下往上进行释放

假设数据库四个层级,库,表,页,记录

假如此时有事务tx1需要在记录A上进行加X锁:
1. 在该记录所在的数据库上加一把意向锁IX
2. 在该记录所在的表上加一把意向锁IX
3. 在该记录所在的页上加一把意向锁IX
4. 最后在该记录A上加上一把X锁
假如此时有事务tx2需要对记录B(假设和记录A在同一个页中)加S锁:
1. 在该记录所在的数据库上加一把意向锁IS
2. 在该记录所在的表上加一把意向锁IS
3. 在该记录所在的页上加一把意向锁IS
4. 最后在该记录B上加一把S锁
假如此时有事务tx3需要在记录A上进行加S锁:
1. 在该记录所在的数据库上加一把意向锁IS
2. 在该记录所在的表上加一把意向锁IS
3. 在该记录所在的页上加一把意向锁IS
4. 发现该记录被锁定(tx1的X锁),那么tx3需要等待,直到tx1进行commit

tips:

  • 共享锁和排它锁不是说只能加在记录级别上,是可以加在各个级别上的

    innodb表锁的获取:

    lock table l read;
    lock table l write;
    unlock tables;
    这是server层的锁(mdl锁)

    从原理上讲innodb也是可以对表加X锁的,但是没有一个具体的命令来触发,也可以把lock table l read; 理解为加X锁

    通常来说不需要加表级别的锁,mysqldump都不加,ddl不支持online的时候就是先对一张表先加一个S锁,现在不一样了

  • 为什么意向锁都是互相兼容的?因为在当前级别上并没有加锁啊

但是在MySQL中没有数据库级别的锁和页级别的锁,这就意味着一共就两层,所有的意向锁都是表锁,意向锁是innodb层级的

tips:

MySQL8.0中所有的锁都在innodb层,现在的锁一部分在innodb层一部分在server层,server层的不好理解

Ⅱ、自增锁

  • 一个表一个自增列,自增锁做自增并发处理
  • auto_increment pk 代表这个列的自增有一把锁
  • 在事务提交前释放

    其他锁在事务提交时才释放
  • Think about

    insert ... select ...

tips:

MySQL的自增存在一个回溯的问题,5.7版本之前都是非持久化的,都是服务启动时候执行下面这个sql获取自增值,从下个位置开始继续自增,如果数据库重启了,之前的自增值可能被重复使用,8.0已解决,这个值会被写到元数据表(innodb引擎)中。

select max(auto_inc_col) from t for update;

2.1 自增列的约束

(root@localhost) [test]> create table t (a int auto_increment, b int) engine = innodb;
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
(root@localhost) [test]> create table t (a int auto_increment, b int, key(b,a)) engine = innodb;
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
(root@localhost) [test]> create table t (a int auto_increment, b int, key(a,b)) engine = innodb;
Query OK, 0 rows affected (0.04 sec)

InnoDB自增列必须被定义为一个key,且必须是这个key的开始部分

WHY?

select max(auto_inc_col) from t for update;

避免重启执行上面这句的时候扫全表 ,myisam是非聚集索引的,不是用这个方式来采集自增值的,8.0虽然持久化了,但还是有这个限制

经测试,myisam自增列也需要被定义为一个key,但是不需要是key的开始部分

2.2 自增的参数

(root@localhost) [test]> show variables like 'auto_increment%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| auto_increment_increment | 1 | -- 步长
| auto_increment_offset | 1 | --初始值
+--------------------------+-------+
2 rows in set (0.01 sec)

多节点全局唯一

N台服务器:A:[offset = 1, increment=N] , B:[offset = 2, increment=N] , C:[offset = 3, increment=N]...N:[offset = N, increment=N]

注意,这不能用来做多主,如果有额外的唯一索引就保证不了全局唯一了

2.3 自增锁分析

session1:

(root@localhost) [test]> create table t_ai_l(a int auto_increment, b int, primary key(a));
Query OK, 0 rows affected (0.02 sec) (root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> insert into t_ai_l values(NULL, 10);
Query OK, 1 row affected (0.00 sec) 事务不提交

session2:

(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> insert into t_ai_l values(NULL, 20);
Query OK, 1 row affected (0.00 sec)

咦?没等待耶,amazing!

AI锁在事务提交前就释放了,类似latch,使用完就释放了

session1&2:

(root@localhost) [test]> rollback;
Query OK, 0 rows affected (0.02 sec)

session1:

(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> insert into t_ai_l values(NULL, 30);
Query OK, 1 row affected (0.00 sec) (root@localhost) [test]> commit;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> select * from t_ai_l;
+---+------+
| a | b |
+---+------+
| 3 | 30 |
+---+------+
1 row in set (0.00 sec)

可以看到虽然rollback,但AI锁是提交过了的,自增值不会跟着回滚,这样自增值就不连续,但连续也没什么用

也就是说,仅仅是这条sql执行的这段时间里,其他session是不可以对这个表操作的,插入过程太长,对insert也会阻塞

执行这条sql的时候,自增是被锁住的,所以插进去之后都是连续的值

2.4 利用sleep()分析自增锁

session1:

(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> insert into t_ai_l (a,b) select NULL, sleep(1) from tmp limit 10000;
~~~

session2:

(root@localhost) [test]> show engine innodb status\G
...
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421958478908128, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 31217775, ACTIVE 10 sec
mysql tables in use 2, locked 2
4 lock struct(s), heap size 1136, 11 row lock(s), undo log entries 10
MySQL thread id 2255, OS thread handle 140482757068544, query id 3006342 localhost root User sleep
insert into t_ai_l (a,b) select NULL, sleep(1) from tmp limit 10000
TABLE LOCK table `test`.`tmp` trx id 31217775 lock mode IS
RECORD LOCKS space id 1408 page no 4 n bits 624 index PRIMARY of table `test`.`tmp` trx id 31217775 lock mode S
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 000001cd15db; asc ;;
2: len 7; hex d4000001760110; asc v ;;
3: len 4; hex 80000001; asc ;; Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000002; asc ;;
1: len 6; hex 000001cd15dc; asc ;;
2: len 7; hex d5000001300110; asc 0 ;;
3: len 4; hex 80000002; asc ;; ... TABLE LOCK table `test`.`t_ai_l` trx id 31217775 lock mode AUTO-INC
TABLE LOCK table `test`.`t_ai_l` trx id 31217775 lock mode IX
...

插入数据过程分析:

  • tmp表被加了IS锁,表中记录被加S锁,注意不会一次性所有记录加锁,是被查到的记录就被锁住,最终事务结束后释放所有锁
  • t_ai_l表上有两个锁AUTO-INC和IX

session2:

(root@localhost) [test]> insert into t_ai_l (a,b) select NULL, sleep(1) from tmp limit 10000;
~~~

session3:

(root@localhost) [test]> show engine innodb status\G
...
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421958478909040, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 31218060, ACTIVE 15 sec setting auto-inc lock
mysql tables in use 2, locked 2
LOCK WAIT 3 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 2255, OS thread handle 140482757068544, query id 3006385 localhost root Sending data
insert into t_ai_l (a,b) select NULL, b from tmp limit 10000
------- TRX HAS BEEN WAITING 15 SEC FOR THIS LOCK TO BE GRANTED:
TABLE LOCK table `test`.`t_ai_l` trx id 31218060 lock mode AUTO-INC waiting
------------------
TABLE LOCK table `test`.`tmp` trx id 31218060 lock mode IS
RECORD LOCKS space id 1408 page no 4 n bits 624 index PRIMARY of table `test`.`tmp` trx id 31218060 lock mode S
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 000001cd15db; asc ;;
2: len 7; hex d4000001760110; asc v ;;
3: len 4; hex 80000001; asc ;; TABLE LOCK table `test`.`t_ai_l` trx id 31218060 lock mode AUTO-INC waiting
---TRANSACTION 31218051, ACTIVE 40 sec
mysql tables in use 2, locked 2
4 lock struct(s), heap size 1136, 40 row lock(s), undo log entries 39
MySQL thread id 2254, OS thread handle 140482756536064, query id 3006383 localhost root User sleep
insert into t_ai_l (a,b) select NULL, sleep(1) from tmp limit 10000
TABLE LOCK table `test`.`tmp` trx id 31218051 lock mode IS
RECORD LOCKS space id 1408 page no 4 n bits 624 index PRIMARY of table `test`.`tmp` trx id 31218051 lock mode S
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 000001cd15db; asc ;;
2: len 7; hex d4000001760110; asc v ;;
3: len 4; hex 80000001; asc ;; Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000002; asc ;;
1: len 6; hex 000001cd15dc; asc ;;
2: len 7; hex d5000001300110; asc 0 ;;
3: len 4; hex 80000002; asc ;;
...

insert into t_ai_l (a,b) select NULL, b from tmp limit 10000 在等待三个锁

  • t_ai_l表上的AUTO-INC锁
  • tmp表上的IS锁
  • tmp表中第一条记录上的S锁

这样设计的初衷是希望批量插入的自增值是连续的,但实际上是牺牲了并发度的

2.5 自增锁的分类

- 说明
insert-like 所有插入语句都属于此类
simple inserts 插入之前能确定插入多少行(insert into table_1 values(NULL, 1), (NULL, 2)

InnoDB中锁的模式的更多相关文章

  1. InnoDB中锁的模式,锁的查看,算法

    InnoDB中锁的模式   Ⅰ.总览 S行级共享锁lock in share mode X行级排它锁增删改 IS意向共享锁 IX意向排他锁 AI自增锁 Ⅱ.锁之间的兼容性 兼 X IX S IS X ...

  2. InnoDB中锁的查看

    Ⅰ. show engine innodb status\G 1.1 实力分析一波 锁介绍的那篇中已经提到了这个命令,现在我们开一个参数,更细致的分析一下这个命令 (root@localhost) [ ...

  3. InnoDB中锁的算法(1)

    Ⅰ.InnoDB锁算法的介绍 首先明确一点,锁锁住的是什么?锁锁住的是索引 Record Lock 单个行记录上的锁 Gap Lock 锁定一个范围,但不包含记录本身 Next-key Lock Ga ...

  4. InnoDB中锁的算法(2)

    Ⅰ.上节回顾 session1: (root@localhost) [test]> select * from l; +---+------+------+------+ | a | b | c ...

  5. InnoDB中锁的算法(3)

    Ⅰ.隐式锁vs显示锁 session1: (root@localhost) [test]> show variables like 'tx_isolation'; +-------------- ...

  6. Innodb中怎么查看锁信息

    一.前言 上一篇说了下innodb中锁的大概意思, 这篇说说怎么查看加的哪些锁.不然后续出现死锁或者锁等待都不知道为什么. 二.底层基础表信息 在学会如何查看有哪些锁信息时, 需要了解一些基础表信息, ...

  7. InnoDB之锁机制

    前两天听了姜老大关于InnoDB中锁的相关培训,刚好也在看这方面的知识,就顺便利用时间把这部分知识做个整理,方便自己理解.主要分为下面几个部分 1. InnoDB同步机制 InnoDB存储引擎有两种同 ...

  8. Innodb中的事务隔离级别和锁的关系

    前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力. ...

  9. Innodb中的事务隔离级别和锁的关系(转)

    原文:http://tech.meituan.com/innodb-lock.html 前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库 ...

随机推荐

  1. 机器人关节空间轨迹规划--S型速度规划

    关节空间 VS 操作空间 关节空间与操作空间轨迹规划流程图如下(上标$i$和$f$分别代表起始位置initial和目标位置final): 在关节空间内进行轨迹规划有如下优点: 在线运算量更小,即无需进 ...

  2. 【Android】解析Paint类中Xfermode的使用

    Paint类提供了setXfermode(Xfermode xfermode)方法,Xfermode指明了原图像和目标图像的结合方式.谈到Xfermode就不得不谈它的派生类PorterDuffXfe ...

  3. 构建自己的 Smart Life 私有云(二)-> 连通 IFTTT & Slack

    博客搬迁至https://blog.wangjiegulu.com RSS订阅:https://blog.wangjiegulu.com/feed.xml 原文链接:https://blog.wang ...

  4. Fluent动网格【13】:网格光顺总结及实例

    光顺(Smoothing)方法是最基本的网格节点更新方法.Fluent提供了三种光顺方法: Spring弹簧光顺 Diffusion扩散光顺 Linearly Elastic Solid光顺 三种方法 ...

  5. return返回两个三元表达式的和,返回不正确,同样要注意在JavaScript中,也是如此

    public string b() { string b = ""; "; } public int c() { public string b() { string b ...

  6. 凭什么相信你,我的CNN模型

    背景 学术界一直困惑的点是"如何让看似黑盒的CNN模型说话",即对它的分类结果给出解释. 这里的解释是指,让模型告诉我们它是通过图片的哪些像素做出判断的,并不是深度学习理论层面的解 ...

  7. [转]java List和数组相互转换方法

    原文地址:https://blog.csdn.net/zjx2016/article/details/78273192 前言在java项目中数组和list集合(这里指ArrayList)经常需要互相转 ...

  8. TPS和QPS的区别和理解

    QPS:Queries Per Second意思是“每秒查询率”,是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准. TPS:是Transactions ...

  9. TCP连接的状态与关闭方式,及其对Server与Client的影响

    1. TCP连接的状态 首先介绍一下TCP连接建立与关闭过程中的状态.TCP连接过程是状态的转换,促使状态发生转换的因素包括用户调用.特定数据包以及超时等,具体状态如下所示: CLOSED:初始状态, ...

  10. BarTender中如何调整数据输入表单的大小?

    BarTender中的表单设计,是一个简单而又复杂的操作.简单的是它提供很多实用的工具,帮助用户实现更多的功能,复杂的是要对其进行排版设计,这就要看小伙伴们的个人要求高低了. 自定义数据输入表单时,你 ...