InnoDB存储引擎的行级锁

前言

InnoDB存储引擎和MyISAM的其中有两个很重要的区别:一个是事务,一个就是锁机制不同。事务之前有介绍,有问题的去补课;锁方面的不同是InnoDB引擎既有表锁又有行锁,表锁的应用和MyISAM表锁用法一样,行锁只有通过有索引的字段作为条件检索的时候,才会使用行级锁,反之则是表锁。

一、隐式加锁

创建表和测试数据

用户表user中id为主键索引,username为普通索引,money字段为普通字段。在非事务环境下,隐式加锁的过程时间非常短,不便研究。下面的栗子都是在事务环境下

CREATE TABLE `user`(
id INT PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(50),
`money` DECIMAL(7,2),
key username(username)
)ENGINE=innodb CHARSET=utf8;

INSERT INTO user(`username`,`money`) VALUES('乔峰',5);
INSERT INTO user(`username`,`money`) VALUES('风清扬',20);

1.行锁

当我们对用户表进行增删改(insert、delete、update)的时候,如果有检索条件中使用到了索引,MySQL服务器会自动给当前操作的表添加行锁。

终端A
更新id为3的记录,id为主键索引,所以会引发行级锁。

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update user set money=money+5 where id=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

终端B
B端在执行update操作的时候,先是光标不停闪烁,且进入锁等待状态,后报锁超时错误

mysql> update user set money=money+5 where id=1;
Query OK, 1 row affected (0.08 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set money=money+12 where id=2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

终端A

A端执行提交(commit),系统会自动释放表锁

mysql> commit;
Query OK, 0 rows affected (0.03 sec)
2.表锁

如果有检索条件(money字段)中没有使用到了索引,MySQL服务器会自动给当前操作的表添加表锁。

终端A

mysql> select * from user;
+----+----------+-------+
| id | username | money |
+----+----------+-------+
|  1 | 乔峰     | 10.00 |
|  2 | 风清扬   | 37.00 |
+----+----------+-------+
3 rows in set (0.02 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update user set money=money+5 where money=93.00;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

终端B

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update user set money=money+12 where id=2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> update user set money=money+12 where id=1;
ERROR 1205 

二、显式加行锁

加锁语句:

SELECT 查询语句 LOCK IN SHARE MODE | FOR UPDATE 

我们只需在正常的查询语句后面加LOCK IN SHARE MODE | FOR UPDATE就能实现添加行级读锁和行级排他锁

1.意向锁

意向锁是InnoDB自动加的,不需用户干预,对于UPDATE、DELETE、INSERT操作,InnoDB会自动给操作的数据加排他锁。 我们在显式加行锁的时候,MySQL服务器会自动给操作表添加一个意向锁。此意向锁是隐式添加的,多个意向锁之间不会产生冲突且相互兼容

2.锁的兼容问题
-共享锁排他锁意向共享锁意向排他锁
共享锁兼容冲突兼容冲突
排他锁冲突冲突冲突冲突
2.1.共享锁兼容

终端A

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user lock in share mode;
+----+----------+-------+
| id | username | money |
+----+----------+-------+
|  1 | 乔峰     | 10.00 |
|  2 | 风清扬   | 37.00 |
+----+----------+-------+
3 rows in set (0.00 sec)

终端B

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user lock in share mode;
+----+----------+-------+
| id | username | money |
+----+----------+-------+
|  1 | 乔峰     | 10.00 |
|  2 | 风清扬   | 37.00 |
+----+----------+-------+
3 rows in set (0.00 sec)
2.2.共享锁和意向排他锁冲突

终端A

mysql> select * from user where id=2 lock in share mode;
+----+----------+-------+
| id | username | money |
+----+----------+-------+
|  2 | 风清扬    | 20.00 |
+----+----------+-------+
1 row in set (0.00 sec)

mysql> update user set money=money+5 where id=2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
2.3.排他锁与其他锁都冲突

终端A

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user where id=2 for update;
+----+----------+--------+
| id | username | money  |
+----+----------+--------+
|  3 | 风清扬    | 37.00  |
+----+----------+--------+
1 row in set (0.00 sec)

终端B

mysql> select * from user where id=2 lock in share mode;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> update user set money=money+5 where id=2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
三、间隙锁

间隙锁是针对一个范围条件的检索时,InnoDB会给符合条件的已有的数据记录的索引项加锁;对于键值在条件范围内但是并不存在的记录,叫做“间隙”,InnoDB也会对这个“间隙”加锁,这种锁机制就是间隙锁
终端A

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user where id > 1 for update;
+----+----------+--------+
| id | username | money  |
+----+----------+--------+
|  3 | 风清扬    | 103.00 |
+----+----------+--------+
1 row in set (0.00 sec)

终端B

mysql> update user set money=money+5 where id=2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> INSERT INTO user(`username`,`money`) VALUES('jack',99);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值