record lock、gap lock、next-key lock 和事务隔离级别例子

目录

  • 一、查看、设置mysql 事务隔离级别
  • 二、Row-level locking
  • Pre Check Before Read Locking
    • 1.LOCK IN SHARE MODE
    • 2.FOR UPDATE
  • 三、gap lock
    • 1.Phantom Rows
    • 2.gap lock
  • 四、next-key lock
  • 五、乐观锁
  • 六、Isolation Levels
    • 1. Read Uncommitted
    • 2.read-committed
    • 3.repeatable-read
    • 4.serializable

一、查看、设置mysql 事务隔离级别

//展示事务隔离级别
show global variables like '%isolation%';
//修改事务隔离级别
set global transaction_isolation ='read-committed';

//事务是否自动提交
show GLOBAL variables LIKE 'autocommit' ;

在这里插入图片描述

二、Row-level locking

Pre Check Before Read Locking

You need to make sure about few points to make the row locking work.

  • First of your table’s storage engine must be set as InnoDB.(MyISAM 不支持行锁)
  • Your row locking query must executes after starting the transaction.
  • Record locks always lock index records, even if a table is defined with no indexes. or such cases, InnoDB creates a hidden clustered index and uses this index for record locking.查询条件就是索引,则会锁该记录。若条件没有index,则会锁整张表(毕竟为了查找那条记录扫描而锁记录代价大),存储引擎层面就会将所有记录加锁后返回,再由MySQL Server层进行过滤。
    但在实际使用过程当中,MySQL做了一些改进,在MySQL Server过滤条件,发现不满足后,会调用unlock_row方法,把不满足条件的记录释放锁 (违背了二段锁协议的约束)。这样做,保证了最后只会持有满足条件记录上的锁,但是每条记录的加锁操作还是不能省略的。可见即使是MySQL,为了效率也是会违反规范的。(参见《高性能MySQL》中文第三版p181)

在真实数据行的锁

1.LOCK IN SHARE MODE

Any lock held with the LOCK IN SHARE MODE clause will allow other transactions to read(using the clause LOCK IN SHARE MODE) the locked row but will not allow other transactions to write on the row until the transaction get committed or rolled back and the lock is released. This is basically a shared/read lock.

SELECT … LOCK IN SHARE MODE适用于两张表存在业务关系时的一致性要求
比如parent、child表,一个parent可以有多个孩子,则会在设计时将child端加外键。从业务角度讲,直接插入child记录是有风险的,因为此child关联的parent可能被其他事务所删除,从而造成数据不一致的风险。正确的做法是select * from parent where c_child_id=100 lock in share mode,锁定了parent表的这条记录,然后执行insert into child(child_id) values (100)就ok了。

2.FOR UPDATE

Any lock held with the FOR UPDATE clause will not allow other transactions to read (using the clause FOR UPDATE), update, or delete the rows until the transaction gets committed or rolled back, releasing the lock. This is basically an exclusive/write lock.
record lock、gap lock、next-key lock 和事务隔离级别例子_第1张图片
适用于操作同一张表时的一致性要求。
电商系统中计算一种商品的剩余数量,在产生订单之前需要确认商品数量>=1,产生订单之后应该将商品数量减1。
①select amount from product where product_name=‘XX’;
②update product set amount=amount-1 where product_name=‘XX’;
如果用LOCK IN SHARE MODE就会出现问题,若此时两个购物订单,则T1、T2会读到相同的amount,若更新,还会造成死锁(在均未超时的情况下)。
此时就应该用for update,若此时两个购物订单,其中T1查到amount,而另一个事务再查同条记录会阻塞;当T1提交后,T2查到结果,再操作提交。

三、gap lock

1.Phantom Rows

The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.
幻读:同一事务,在不同时间,执行相同的查询语句,产生不同的结果行(或多或少)。

举例:
在id列有索引,想要读,然后锁住id>100的所有行。

SELECT * FROM child WHERE id > 100 FOR UPDATE;

假设表中包含id=90、id=102,如果不对间隙(gap)进行锁定,则另一个事务可以插入id=101的行。其他事务会看到新插入的行。

模拟:
在read commit 级别下,并没有解决幻读问题,则可以在此级别下模拟
加粗样式record lock、gap lock、next-key lock 和事务隔离级别例子_第2张图片

2.gap lock

gap lock:锁定一个范围,但不包括记录本身。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。

gap:A place in an InnoDB index data structure where new values could be inserted.
也就是说,gap是索引树中插入新记录的空隙。

A gap lock is a lock on a gap between index records, or a lock on the gap before the first or after the last index record.
将范围内的空隙锁住

SELECT * FROM child WHERE id between 1 and 10 FOR UPDATE; //锁住[1-10]
SELECT * FROM child WHERE id < 10 FOR UPDATE; //锁住>10
SELECT * FROM child WHERE id > 10 FOR UPDATE; //锁住<10

Gap locking is not needed for statements that lock rows using a unique index to search for a unique row. (This does not include the case that the search condition includes only some columns of a multiple-column unique index; in that case, gap locking does occur.) For example, if the id column has a unique index, the following statement uses only an index-record lock for the row having id value 100 and it does not matter whether other sessions insert rows in the preceding gap:
对于使用唯一索引来锁定唯一行来锁定行的语句,不需要间隙锁定。 (这不包括搜索条件是联合索引的某些列;在这种情况下,会发生间隙锁定。)例如,如果id列具有唯一索引,则以下语句仅使用 ID值为100的行的索引记录锁,其他会话是否在前面的间隙中插入行都没有关系:

SELECT * FROM child WHERE id = 100;

If id is not indexed or has a nonunique index, the statement does lock the preceding gap.
若搜索条件不是索引或唯一索引,则会锁住preceding gap.

四、next-key lock

A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.
next-key lock:Row-level locking + gap lock
repeatable-read用next-key lock避免幻读

五、乐观锁

InnoDB是用乐观锁
MySQL InnoDB MVCC实现:https://blog.csdn.net/jiangshangchunjiezi/article/details/105802025)

【将MVCC理解才能较深入理解Isolation levels】

六、Isolation Levels

record lock、gap lock、next-key lock 和事务隔离级别例子_第3张图片

以下是普通查询,也就是select … from… 是快照读read view

1. Read Uncommitted

record lock、gap lock、next-key lock 和事务隔离级别例子_第4张图片

2.read-committed

避免了脏读(dirty read):是用read view解决的
record lock、gap lock、next-key lock 和事务隔离级别例子_第5张图片

3.repeatable-read

避免了不可重复读和幻读:不可重复读是MVCC解决的,幻读是next-key lock解决的
record lock、gap lock、next-key lock 和事务隔离级别例子_第6张图片

4.serializable

record lock、gap lock、next-key lock 和事务隔离级别例子_第7张图片

参考:https://blog.toadworld.com/2018/01/11/explaining-innodb-explicit-locking-mechanisms
https://blog.csdn.net/cug_jiang126com/article/details/50544728
https://tech.meituan.com/2014/08/20/innodb-lock.html

你可能感兴趣的:(mysql)