参考文章:
http://www.cnblogs.com/zhoujinyi/p/3435982.html
https://www.cnblogs.com/janehoo/p/5603983.html
https://www.cnblogs.com/aipiaoborensheng/p/5767459.html
0 锁的分类以及加锁方式
- 行锁
- s锁,share lock共享锁
- x锁,排他锁
- 表锁
- 意向共享锁 IS
- 意向排他锁 IX
- 加锁方式
- select * from tb_name lock in share mode;
- select * from tb_name for update;
1 行锁
1 在不通过索引条件查询的时候,InnoDB确实使用的是表锁,而不是行锁
mysql> show create table tab_no_index;
+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table
|
+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tab_no_index | CREATE TABLE `tab_no_index` (
`id` int(11) DEFAULT NULL,
`name` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
---`session 1`
mysql> select * from tab_no_index where id = 1 for update;
+------+------+
| id | name |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
--- `session 2`
mysql> select * from tab_no_index for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> select * from tab_no_index;
+------+------+
| id | name |
+------+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
+------+------+
4 rows in set (0.00 sec)
2 由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。应用设计的时候要注意这一点。
---session 1 加排它锁
mysql> select * from tab_has_index where id =1 for update;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
+----+------+
1 row in set (0.00 sec)
--- session 2
mysql> select * from tab_has_index where id =1;
+----+------+
| id | name |
+----+------+
| 1 | 1 |
+----+------+
1 row in set (0.00 sec)
-- 会话2 加排它锁
mysql> select * from tab_has_index where id =1 for update;
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> select * from tab_has_index where id =2 for update;
+----+------+
| id | name |
+----+------+
| 2 | 2 |
+----+------+
1 row in set (0.00 sec)
3 当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁
4 即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比 如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真 正使用了索引