前提
CREATE TABLE `song_rank` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`songId` int(11) NOT NULL,
`weight` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `songId_idx` (`songId`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
+------------+
| @@version |
+------------+
| 5.7.21-log |
+------------+
1 row in set (0.00 sec)
关闭自动提交
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 0 |
+--------------+
1 row in set (0.00 sec)
表中数据
mysql> select * from song_rank;
+----+--------+--------+
| id | songId | weight |
+----+--------+--------+
| 1 | 10 | 30 |
| 2 | 20 | 30 |
+----+--------+--------+
2 rows in set (0.01 sec)
锁类型
主要说下兼容性和锁模式类型的锁
1.共享锁与排他锁
Innodb实现了标准的行级锁
- 共享锁(s锁):允许持锁事务读取一行
- 排它锁(x锁):允许持锁事务更新或删除一行
场景:
事务1持有行 r 的 s 锁,另外一个事务2请求 r 锁时会如下处理
- 事务2请求 s 锁被允许,结果事务1,事务2都持有 r 行的 s 锁
- 事务2请求 x 锁不能被立即允许
事务1持有 r 的 x 锁,那么事务2请求 r 的 x,s 锁都不能被立即允许,事务2必须等待事务1释放 x 锁才可以,因为 x 锁不能与任何锁兼容
2.意向锁
- 意向共享锁(IS锁):事务想要获取一个表中某几行的共享锁
- 意向排它锁(IX锁):事务想要获取一个表中某几行的排他锁
场景:
- 事务1在表加上 s 锁后,事务2 想要更改某行记录,需要添加 IX 锁,由于不兼容,所以需要等待 s 锁释放
- 如果事务1在表1上加了 IS 锁,事务2添加的 IX 锁与 IS 锁兼容,就可以操作
3.Innodb存储引擎中锁的兼容性如下
4.记录锁
记录锁是最简单的行锁,仅仅锁住一行
SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE
记录锁永远都是加在索引上的,即使一个表没有索引,InnoDB也会隐式的创建一个索引,并使用这个索引实施记录锁。 会阻塞其他事物对其插入,更新,删除
记录锁的事物数据(关键词:lock_mode X locks rec but not gap)
5.间隙锁
- 间隙锁是一种加在两个索引之间的锁,或者加在第一个索引之前,或最后一个索引之后的间隙。
- 使用间隙锁锁住的是一个区间,而不仅仅是这个区间中的每一条数据。
- 间隙锁只阻止其他事务插入到间隙中,他们不阻止其他事务在同一个间隙上获得间隙锁,所以 gap x lock 和 gap s lock 有相同的作用。
6.next-key
Next-key锁是记录锁和间隙锁的组合,它指的是加在某条记录以及这条记录前面间隙上的锁。
7.插入意向锁(Insert Intention)
- 插入意向锁是在插入一行记录操作之前设置的一种间隙锁,这个锁释放了一种插入方式的信号,亦即多个事务在相同的索引间隙插入时如果不是插入间隙中相同的位置就不需要互相等待。
- 假设有索引值4、7,几个不同的事务准备插入5、6,每个锁都在获得插入行的独占锁之前用插入意向锁各自锁住了4、7之间的间隙,但是不阻塞对方,因为插入行不冲突。
操作回溯
事物1
begin;
insert into song_rank(songId,weight) values(15,100) on duplicate key update weight=weight+1; (Query OK, 1 row affected (0.00 sec) )
事物2
begin;
insert into song_rank(songId,weight) values(16,100) on duplicate key update weight=weight+1; //被阻塞
事物3
begin;
insert into song_rank(songId,weight) values(18,100) on duplicate key update weight=weight+1; //被阻塞
事物1
rollback;
事物2
Query OK, 1 row affected (40.83 sec)
事物3
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
insert加锁策略
死锁
当两个或两个以上的事务相互持有和请求锁的时候,如果形成了一个循环的依赖关系,就会产生死锁。