什么是间隙锁

一直都不明白什么是间隙锁和间隙锁的意义,网上都是互相抄来抄去的内容,要不就是面经里面的套话,反正说的都不是人话,估计写的人自己也不明白再说什么。

后来看了一本正经的数据库的书,一句话就说明白了,间隙锁锁的是尚不存在的资源。我们平时说道多线程的锁也好,分布式锁也好,锁的都是某个存在的且需要共享互斥的资源,而间隙锁锁定了一个范围内还不存在资源,避免其他事物在这个范围中创建这些不存在的资源。这也就是幻读导致的问题。

image.png

创建表结构

  1. CREATE TABLE `user_lock` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `name` varchar(45) DEFAULT NULL,
  4. `age_idx` int(11) DEFAULT NULL,
  5. `age_uidx` int(11) DEFAULT NULL,
  6. `age_nidx` int(11) DEFAULT NULL,
  7. PRIMARY KEY (`id`),
  8. UNIQUE KEY `uidx_age` (`age_uidx`),
  9. KEY `idx_name` (`name`),
  10. KEY `idx_age` (`age_idx`),
  11. KEY `idx_name_age` (`name`,`age_idx`)
  12. ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

初始化数据

  1. INSERT INTO `test_isolation`.`user_lock` (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('10', 10, 10, 10);
  2. INSERT INTO `test_isolation`.`user_lock` (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('20', 20, 20, 20);
  3. INSERT INTO `test_isolation`.`user_lock` (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('30', 30, 30, 30);
  4. INSERT INTO `test_isolation`.`user_lock` (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('40', 40, 40, 40);
  5. INSERT INTO `test_isolation`.`user_lock` (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('50', 50, 50, 50);

T1 - 设置隔离级别

REPEATABLE READ

  1. SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
  2. select @@global.transaction_isolation,@@transaction_isolation;

image.png

T2 - 设置隔离级别

REPEATABLE READ

  1. SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
  2. select @@global.transaction_isolation,@@transaction_isolation;

image.png

T1 - 事务1开启,删除或更新一条记录

  1. start transaction;
  2. DELETE FROM test_isolation.user_lock where age_idx = 20;

image.png
OR

  1. start transaction;
  2. UPDATE test_isolation.user_lock SET name = '20A', age_idx = 20 WHERE age_idx = 20;

image.png

T2 - 事务2受间隙锁影响的插入操作

允许的范围


image.png

  1. start transaction;
  2. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('9', 9, 9, 9);
  3. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('30', 30, 300, 30);
  4. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('31', 31, 31, 31);
  5. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('39', 39, 39, 39);
  6. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('40', 40, 400, 40);
  7. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('41', 41, 41, 41);
  8. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('49', 49, 49, 49);
  9. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('50', 50, 500, 50);
  10. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('51', 51, 51, 51);

image.png

间隙锁范围


image.png

  1. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('10', 10, 100, 10);
  2. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('11', 11, 11, 11);
  3. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('19', 19, 19, 19);
  4. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('20', 20, 200, 20);
  5. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('21', 21, 21, 21);
  6. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('29', 29, 29, 29);

image.png

T2 - 事务2受行锁影响的更新操作操作

允许范围

  1. UPDATE test_isolation.user_lock SET name = '10', age_idx = 10, age_nidx = 10 WHERE age_idx = 10;
  2. UPDATE test_isolation.user_lock SET name = '30', age_idx = 30, age_nidx = 30 WHERE age_idx = 30;

image.png

锁的范围

  1. UPDATE test_isolation.user_lock SET name = '20', age_idx = 20, age_nidx = 20 WHERE age_idx = 20;

image.png

T2 - 事务2受行锁影响的删除操作

允许范围

  1. DELETE FROM test_isolation.user_lock WHERE age_idx = 10;
  2. DELETE FROM test_isolation.user_lock WHERE age_idx = 30;

image.png

锁的范围

  1. DELETE FROM test_isolation.user_lock WHERE age_idx = 20;

image.png

T1 - 事务1提交事务释放间隙锁

  1. COMMIT

image.png

T2 - 事务2不再受间隙锁影响了

  1. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('10', 10, 100, 10);
  2. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('11', 11, 11, 11);
  3. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('19', 19, 19, 19);
  4. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('20', 20, 200, 20);
  5. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('21', 21, 21, 21);
  6. INSERT INTO test_isolation.user_lock (`name`, `age_idx`, `age_uidx`, `age_nidx`) VALUES ('29', 29, 29, 29);
  7. UPDATE test_isolation.user_lock SET name = '20', age_idx = 20, age_nidx = 20 WHERE age_idx = 20;
  8. DELETE FROM test_isolation.user_lock WHERE age = 20;
  9. COMMIT

image.png