对于 SELECT … FOR UPDATE 我们知道除了有查询的功能外,还会对查询结果进行加锁,而且是悲观锁。
那么它到底是「行锁」还是「表锁」,这就要根据具体的使用场景来区分了,如下:
- WHERE 条件中有使用「主键」或者「索引」的话,那就是 行锁
- WHERE 条件中都是「普通字段」,那就是 表锁
这里拿 t_staff 表来简单举个例子,如下:
CREATE TABLE `t_staff` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`code` VARCHAR (25) NOT NULL,
`name` VARCHAR ( 255 ) NOT NULL,
PRIMARY KEY ( `id` ),
KEY `idx_code` ( `code` ) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8
我们可以看到,上边这个 t_satff 表:
- 主键为 id
- 字段 code 上加了唯一索引
为了更好的说明后边的例子,在 t_staff 表中 INSERT 一些数据:
mysql> SELECT * FROM t_staff
+----+----+----+
| id | code | name |
| 1 | 001 | 小一 |
| 2 | 002 | 小二 |
| 3 | 003 | 三三 |
| 4 | 004 | 小四 |
| 5 | 005 | 小五 |
| 6 | 006 | 小六 |
| 7 | 007 | 小七 |
+----+----+----+
OK,数据都准备好了!让我们通过下边三个场景来简单说明下 FOR UPDATE 到底是「行锁」还是「表锁」。
-
WHERE 中使用主键
mysql> SELECT * FROM t_staff WHERE id = 1 FOR UPDATE
只锁定 id=1 的数据,行锁,此时除该条数据以外都允许 update。
-
WHERE 中使用带索引的字段
mysql> SELECT * FROM t_staff WHERE code = ’007’ FOR UPDATE
只锁定 code=007 的数据,行锁,此时除该条数据以外都允许 update。
-
WHERE 中使用普通字段
mysql> SELECT * FROM t_staff WHERE name = ’三三’ FOR UPDATE
由于 name 不是主键也没加索引,所以是表锁,所有数据此时都不能 update。