# 测试表
# !!!!!!
# 若给num加上普通的非唯一索引
# 范围查询id时可能不会使用主键导致锁表
# 可以使用force index(pri)强制使用主键
# 比如: select * from test where id between 9 and 11
# 可能会使用num索引导致锁表
# 强制使用主键即可:
# select * from test force index(pri) where id between 9 and 11
# !!!!!!
create table `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`num` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
# 测试数据
INSERT INTO `test` VALUES (1, 1);
INSERT INTO `test` VALUES (3, 2);
INSERT INTO `test` VALUES (6, 3);
INSERT INTO `test` VALUES (9, 8);
INSERT INTO `test` VALUES (11, 15);
记录锁是作用在索引上的锁。比如:SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;只会阻止其他事务插入、修改、删除t.c1等于10的行。
记录锁总是作用在索引上,如果表没有索引,InnoDB会创建隐式索引,并作用在这个隐式索引上。
共享锁(Shared Locks)
共享锁允许其他事务加共享锁读取,但是不允许其他事务去做修改
# 客户端A
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test where id = 1 lock in share mode;
+----+-----+
| id | num |
+----+-----+
| 1 | 1 |
+----+-----+
1 row in set (0.00 sec)
# 客户端B
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test where id = 1 lock in share mode;
+----+-----+
| id | num |
+----+-----+
| 1 | 1 |
+----+-----+
1 row in set (0.00 sec)
# 客户端A
# 操作被阻塞一段时间后操作超时
mysql> update test set num = 11 where id = 1;
# ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
# 客户端B也修改同一条数据
# mysql检测到死锁
# 中断当前事务
mysql> update test set num = 112 where id = 1;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
MySQL InnoDB锁和事务
准备工作
测试环境
环境:MySQL5.7,InnoDB,默认隔离级别(Repeatable Read)
关闭autocommit
MySQL默认开启autocommit自动提交模式,也就是除非手动开启一个事务,否则每个操作都会当作一个单独的事务然后自动提交。
autocommit模式设置
测试操作
分别启动客户端A和B,客户端A关闭autocommit。
锁类型
记录锁
行锁
(Record Locks)记录锁是作用在索引上的锁。比如:
SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;
只会阻止其他事务插入、修改、删除t.c1
等于10
的行。记录锁总是作用在索引上,如果表没有索引,InnoDB会创建隐式索引,并作用在这个隐式索引上。
共享锁(Shared Locks)
共享锁允许其他事务加共享锁读取,但是不允许其他事务去做修改
排它锁(Exclusive Locks)
排它锁又称为写锁(简记为X锁),若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。
间隙锁(Gap Locks)
概念
间隙锁是索引记录之间,或者第一个索引记录之前,或者最后一个索引记录之后的区间上的锁。比如:
SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;
会阻止其他事务添加10~20
之间的记录,因为这个范围内的值都被锁上了。间隙锁设置
可以通过以下两种方式查看间隙锁是否开启:
innodb_locks_unsafe_for_binlog
参数默认为OFF
,即开启间隙锁,此参数为只读参数,关闭在mysql配置文件的[mysqld]
配置项中添加如下配置:操作测试
分别启动客户端A和B,客户端A关闭autocommit。
意向共享锁/意向排他锁(Intention Shared and Exclusive Locks)
临键锁(Next-key Locks)
事务隔离级别
Mysql默认隔离级别为reapeatable-read