【数据库】—— Mysql实现事务隔离级别的方式 — LBCC/锁

前言

  这次咱们来分析一波事务隔离级别的其中一种实现方式,锁

  涉及到的知识点

  锁究竟锁住的是什么;

  共享锁、排它锁、自增锁

  临键锁、间隙锁、记录锁

 

正文

  锁

  锁的类型

   从粒度上划分,可以分为行锁和表锁(基于innodb引擎)

   从类型上划分,可以分为共享锁、排他锁、意向共享锁、意向排它锁、自增锁

    共享锁 又称读锁,简称S锁

     共享锁允许多个事务对于同一数据可以共享同一把锁,能访问到数据,但是只能读不能修改

     加锁释放锁方式

      select * form student where id=1 LOCK IN SHARE MODE

      commit/rollback

    排它锁 又称写锁,简称X锁

     排它锁不能与其他任何锁并存,如一个事务获取一个数据行的排他锁,其他事务就不能在获取该行的锁(共享锁、排它锁),只有该获取了排它锁的事务是可以对数据进行读取和修改

     加锁释放锁方式

      自动:delete / update / insert / 默认加锁

      手动 select * from student where id = 1  FOR UPDATE

      commit/rollback

    意向锁 为innodb引擎维护的,用户不能主动操作,为表级别的锁,在加共享锁或排他锁之前,系统会自动加上其对应的意向锁,换言之,如果一个表中如果有意向锁,则其表中必定有某些行持有期对应的行锁

    意向锁,可以也理解成一种标记,当一个需要锁表的操作过来的时候,发现此表存在意向锁,那么我也就不需要一行一行的扫秒、加锁了。

    自增锁 是针对自增列自增长的一个特殊的级别锁

    新增数据时,若事务未提交,ID将永久丢失

    模拟一种情景,不好截图,请脑补:新建一张表,主键id自增和name;开启事务 插入一条数据 并提交;后又连续插了几天数据,现在id为5;此时再开启事务 插入一条数据,然后回滚;当我在插入数据时,这是新数据的id为7。

    这就是自增锁。

 

  锁的内容

   行锁,锁的是什么东西,先看一个表结构,不特别解释,下面都以此表为例。

   【数据库】—— Mysql实现事务隔离级别的方式 — LBCC/锁_第1张图片

   先抛结论吧:行锁,其实锁的并不是行,锁的是索引

   1、如果一个事务内锁的是name,此时name上没有索引,他就不知道该怎么办了,就只能锁定了全表。比如:

   事务1:

BEGIN;

SELECT * FROM t2 WHERE name = '1' for update;

COMMIT;

ROLLBACK;

   事务2:

BEGIN;

SELECT * FROM t2 WHERE name = '4' for update;

COMMIT;

ROLLBACK;

   第二个事务是读不到数据的,因为锁定了全表,而不只是一行,如果此时,两个事务都是以id为条件,那就可以查到数据了。

 

   2、假定此时给name建立索引,如果一个事务内锁的是name,第二个事务内也不能通过其对应的id找到其对应的数据,但是和其他行数据不冲突。比如:

   事务1:

BEGIN;

SELECT * FROM t2 WHERE name = '1' for update;

COMMIT;

ROLLBACK;

   事务2:

BEGIN;

SELECT * FROM t2 WHERE id = 1 for update;

COMMIT;

ROLLBACK;

   提示:加锁时一定要加载索引上,避免锁定全表,同时索引失效时也是同样的道理

 

  行锁的算法

   因为临键锁的存在,所以innodb中,Repeatable Read下就已经可以解决幻读的问题了。

   Next-Key 临键锁

   临键锁是innodb上默认的行锁算法。在一些情况下会退化成间隙锁或记录锁

   同样以上面的表结构为例,有4条记录,划定了5个区间,如果把记录划分到左边的区间内,改为左开右闭。

   我们这就可以暂定理解为这几个概念,记录,间隙,临键,看上面的图的话,应该是可以理解的。

BEGIN;
			
SELECT * FROM t2 WHERE id > 4 AND id < 9 for update
			
COMMIT
			
ROLLBACK

    看上面的sql语句,根据临键锁的算法,此时会锁定查询出的数据7所在的区间,以及7所在区间的下一个区间,所以此时的锁定的区间为:(4,7]、(7,10]。

   此时,在这几个区间内都会被锁定的,即使此时插入一个为id为5的数据。

 

   如果查询的数据为空时,退化成间隙锁

 

   Gap 间隙锁

BEGIN;
			
SELECT * FROM t2 WHERE id > 4 AND id < 7 for update
			
SELECT * FROM t2 WHERE id = 5 for update
			
COMMIT
			
ROLLBACK

   上面两个查询的均是锁定(4,7) 区间的情况,这时的两个语句都是没有查到任何内容。

   间隙锁有一个特点为,此时一个事务锁定(4,7),允许另一个间隙锁读取此区间的记录,但仍不可再次区间插入数据

 

   Record 记录锁

   唯一性(主键/唯一)索引,条件为精准匹配,退化成Record锁
   非唯一索引,精准匹配时,会锁记录的左右两个开区间

BEGIN;
			
SELECT * FROM t2 WHERE id = 4 for update
			
COMMIT

ROLLBACK

结语

  Hello Wrold

你可能感兴趣的:(MySQL)