mysql之innodb引擎之lock锁

目录

锁的类型

行锁

意向锁

事务中的读

1.锁定读:

2.非锁定读

锁的算法

锁超时

死锁

锁的表


锁的类型

mysql锁一般有两种类型,一种是latch,该锁是mysql程序的线程锁,快速释放,相当于java里面的syn.还有一种是lock,这种锁是针对innodb事务的,分为行锁和表锁.

行锁

行锁分为S锁和X锁,S锁是共享锁,X锁是排他锁.如下图

S 共享 事务读某行
X 排他 事务修改某行

它们的兼容性,S锁之间兼容,只要有X锁就不兼容。如下

  S X
S
X

举个例子,如果有一个事务针对某行启动了一个共享锁S,那么另一个事务也希望启动共享锁S要读改行,那是畅通无阻的,但是如果另一个事务希望启动X锁去修改,那么会被阻塞,直到S锁释放。

意向锁

行锁是细粒度地锁。在添加行锁之前,为了效率,还要添加粗粒度的锁-意向锁,代表着我将要加哪一块数据锁了。mysql的意向锁比较简单,就是表级别的,如下:

IS 意向共享 事务将要进一步对数据加S锁
IX 意向排他 事务将要进一步对数据加X锁

他们之间的兼容性如下:

  IS IX S X
IS Y Y Y N
IX Y Y N N
S Y N Y N
X N N N N

事务中的读

1.锁定读:

由于事务具有隔离性,所以事务内读取数据有可能不是最新的。那么如何在事务里每次都能够读取到最新的数据呢?其实依据上面的知识就可以,

这需要了解lock in share mode和for update的用法,其中lock in share mode开启了S锁,for update开启了X锁。

大概如下sql语句在事务中开启了S锁:

select name from user where id = 1 lock in share mode

那么由于兼容性问题,不管是lock in share mode还是for update,在遇到其他X锁时,都会被阻塞,直到其他X锁释放,便获取到了最新的数据,并且给改行加上S/X锁。

那么这就是所谓的一致性锁定读。读的就是最新的。

2.非锁定读

在面对事务中普通的读,读出来的又是什么样的呢?

这个要看事务的隔离级别了。

如果隔离级别是repatable,这是innodb的默认隔离级别,读出来的是当前事务开启时的快照。所以即使有其他事务修改,依然读的是老数据。

如果隔离级别 是read commited,读出来的是所有事务里面最新提交的快照。以至于这能产生幻读。

锁的算法

innodb锁的算法主要有三种:

record lock行锁,这是一种基础算法

gap  lock间隙锁,这是一种基础算法,跟索引息息相关的

next-key lock mysql使用的就是这种算法,结合record和gap的锁。

这个我明白的不多,先举例子说明下gap锁吧:

如果某个索引key有 1 3 5 9 四个索引值。

gap会分区间(0,1)(1,3)(3,5)(5,9)(9,...)

注意区间是小括号,都不包括区间点。

如果此时要锁定3,gap锁其实不会去锁定3,而是会锁定(1,3)这个区间,是区间点前面那个区间,注意不包括3这个区间点.

但next-key是升级版,如果要锁定3,nextkey会锁定(1,3】和(3,5),这相当于包括了3以及前后两个区间,这锁了一大片区域。我们知道这一大片区域实际上是不存在的,是数据库缺少的记录,如果要加锁,那就只能是为了insert语句,那么gap的目的就呼之欲出了,就是为了数据插入的串行化。

另外,如果索引是唯一索引,next-key会降级为record lock,不再加区间,而是只有该行。

锁超时

加锁是有时间限制的,如果超时了就释放掉,也可以设置超时回滚。

innodb_lcok_wait_timeout=60  动态
innodb_rollback_on_timeout=OFF 静态

死锁

怎么产生死锁?如下AB两个操作

A:

begin;

select * from user where id = 1 for update

B:

begin;

select * from user where id = 2 for update

select * from user where id = 1 for update //B被锁

A:

select * from user where id = 2 for update //A被锁

通过上面有超时时间,我们可以知道即使是死锁,到了超时时间就自动释放了,其实并不影响什么,但是在并发里,如果什么都不做的话会严重影响性能。所以innodb就做了一个自动检测死锁的机制,一旦发生死锁,立即检测到并报异常,且必然回滚。

innodb检测死锁的机制是采用环形检测

锁的表

怎么排查锁,很好的是,innodb下有专门的表存放锁:

information_schema.INNODB_TRX

information_schema.INNODB_LOCKS

information_schema.INNODB_LOCK_WAITS

猜你喜欢

转载自blog.csdn.net/dmw412724/article/details/106788750
今日推荐