Mysql 行锁 间隙锁 临键锁
mysql 中 innodb 存储引擎支持行锁,我们平常默认使用的也是innodb存储引擎,因为innodb 引擎中有mvcc 的控制,所以我们要想测试的时候就需要手动来显示加锁共享锁 select .... lock in share mode排他锁 select ... for update insert update delete
行锁
mysql 中 innodb 存储引擎支持行锁,我们平常默认使用的也是innodb存储引擎,因为innodb 引擎中有mvcc 的控制,所以我们要想测试的时候就需要手动来显示加锁
- 共享锁 select .... lock in share mode
- 排他锁 select ... for update insert update delete
演示
有以下表
+----+------+------+
| id | name | addr |
+----+------+------+
| 1 | xxx | 1 |
| 4 | ccc | 2 |
| 7 | 1 | 4 |
| 10 | fff | 6 |
+----+------+------+
其中id 为自增主键
开启两个客户端,设置事务手动提交
客户端1 | 客户端2 |
mysql> mysql> | mysql> mysql> |
mysql> select *from student where id = 1 lock in share mode; mysql> | mysql> select *from student where id = 1 lock in share mode; mysql> |
select *from student where id =1 for update ; (被阻塞) | |
mysql> commit; Query OK, 0 rows affected (0.01 sec) | |
mysql> select *from student where id =1 for update ; +----+------+------+ | id | name | addr | +----+------+------+ | 1 | xxx | 1 | +----+------+------+ 1 row in set (0.00 sec) |
由上表我们可以得出,共享锁可以多个客户端获取,当客户端1要获取排他锁的时候,因为客户端2事务没有提交,依然占有共享锁,所以客户端1被阻塞,直至客户端2事务提交,同样排他锁的获取也是独占的
间隙锁
表
+----+------+------+
| id | name | addr |
+----+------+------+
| 1 | xxx | 1 |
| 4 | ccc | 2 |
| 7 | 1 | 4 |
| 10 | fff | 6 |
+----+------+------+
客户端1 | 客户端2 |
mysql> set autocommit=0; mysql> | mysql> set autocommit=0; mysql> |
mysql> select *from student where id >20 for update ; Empty set (0.00 sec) | |
mysql> (被阻塞) | |
commit; | |
插入成功 |
客户端1加排他锁来查询大于20的记录,客户端2在插入11的时候会被阻塞,这是因为,客户端1在查询的时候会对记录加间隙锁,我们当前表的间隙有 (负无穷,1),(1,4),(4,7),(7,10),(10,正无穷),当我们执行 select *from student where id >20 for update ;的时候就会对 (10,正无穷)加锁,所以客户端2会被阻塞,但是这里的10是开区间,也就是说如果客户端2对10进行修改是不会阻塞的。同样如果我们执行 select *from student where id >7 and id <10 for update ; 就会对(7,10)加间隙锁,这里的间隙锁都是没有加在记录上,如果加在了记录上就会变成临键锁,即行锁加间隙锁
临键锁
表
+----+------+------+
| id | name | addr |
+----+------+------+
| 1 | xxx | 1 |
| 4 | ccc | 2 |
| 7 | 1 | 4 |
| 10 | fff | 6 |
+----+------+------+
客户端1 | 客户端2 |
mysql> set autocommit=0; Query OK, 0 rows affected (0.00 sec) | mysql> set autocommit=0; Query OK, 0 rows affected (0.00 sec) |
mysql> select *from student where id >4 and id <10 for update; +----+------+------+ | id | name | addr | +----+------+------+ | 7 | 1 | 4 | +----+------+------+ 1 row in set (0.00 sec) | |
mysql> insert into student values(8,'x','x'); (被阻塞) |
客户端1执行select *from student where id >4 and id <10 for update;会对(4,7】,(7,10】加锁,即 7和10 也会被锁住,即间隙(4,7),(7,10)和 行锁 7 和10;但是对4进行修改将不会阻塞
注意
上述的所有操作都是基于索引的,如果不通过索引加锁的话,锁就会升级为表锁,索引失效也会升级为表锁,其次在演示的时候所有的操作都显示的加锁,因为mvcc机制,不显示加锁的话会产生快照读
更多推荐
所有评论(0)