网站首页 > 文章中心 > 其它

mysql怎么加gap锁_mysql gap锁原理

作者:小编 更新时间:2023-10-24 19:11:57 浏览量:413人看过

mysql默认隔离级别怎么加锁

修改方法

systemd unit file 里支持的资源隔离配置项,如常见的:

mysql怎么加gap锁_mysql gap锁原理-图1

CPUQuota=value

该参数表示服务可以获取的最大 CPU 时间,value 为百分数形式,高于 100% 表示可使用?1 核以上的?CPU.与 cgroup cpu 控制器?cpu.cfs_quota_us?配置项对应.

MemoryLimit=value

该参数表示服务可以使用的最大内存量,value 可以使用 K, M, G, T 等后缀表示值的大小.与 cgroup?memory 控制器?memory.limit_in_bytes?配置项对应.

READ UNCOMMITTED ? ? ? 未提交读,可以读取未提交的数据.

READ COMMITTED ? ? ? ? 已提交读,对于锁定读(select with for update 或者 for share)、update 和 delete 语句,InnoDB 仅锁定索引记录,而不锁定它们之间的间隙,所以呢允许在锁定的记录旁边自由插入新记录. ? ? ? ? ? ? ? ? ? ?

Gap locking 仅用于外键约束检查和重复键检查.

REPEATABLE READ ? ? ? ?可重复读,事务中的一致性读取读取的是事务第一次读取所建立的快照.

数据范围全集组成

SQL 语句根据条件判断不需要扫描的数据范围(不加锁);

mysql怎么加gap锁_mysql gap锁原理-图2

SQL 语句根据条件扫描到的可能需要加锁的数据范围;

以单个数据范围为例,数据范围全集包含:(数据范围不一定是连续的值,也可能是间隔的值组成)

mysql读数据时怎么加写锁

加锁情况与死锁原因分析

为方便大家复现,完整表结构和数据如下:

+c1+ int(11) NOT NULL AUTO_INCREMENT,

PRIMARY KEY (+c1+),

) ENGINE=InnoDB

死锁日志如下:

INSERT INTENTION LOCK

但是插入意向锁是客观存在的,我们可以在官方手册中查到,不可忽略:

Prior to inserting the row, a type of gap lock called an insert intention gap lock is set. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap.

当插入一条记录时,会去检查当前插入位置的下一条记录上是否存在锁对象,如果下一条记录上存在锁对象,就需要判断该锁对象是否锁住了 gap.如果 gap 被锁住了,则插入意向锁与之冲突,进入等待状态(插入意向锁之间并不互斥).最后提醒一下大家这把锁的属性:

① 它不会阻塞其他任何锁;

在学习 MySQL 过程中,一般只有在它被阻塞的时候才能观察到,所以这也是它常常被忽略的原因吧...

GAP LOCK

在此例中,另外一个重要的点就是 gap lock,通常情况下我们说到 gap lock 都只会联想到 REPEATABLE-READ 隔离级别利用其解决幻读.但实际上在 READ-COMMITTED 隔离级别,也会存在 gap lock ,只发生在:唯一约束检查到有唯一冲突的时候,会加 S Next-key Lock,即对记录以及与和上一条记录之间的间隙加共享锁.

通过下面这个例子就能验证:

有个困惑很久的疑问:出现唯一冲突需要加 S Next-Key Lock 是事实,但是加锁的意义是什么?还是说是通过 S Next-Key Lock 来实现的唯一约束检查,但是这样意味着在插入没有遇到唯一冲突的时候,这个锁会立刻释放,这不符合二阶段锁原则.这点希望能与大家一起讨论得到好的解释.

如果是在 REPEATABLE-READ,除以上所说的唯一约束冲突外,gap lock 的存在是这样的:

对于 gap lock,相信 DBA 们的心情是一样一样的,所以我的建议是:

① 在绝大部分的业务场景下,都可以把 MySQL 的隔离界别设置为 READ-COMMITTED;

锁冲突矩阵

前面我们说的 GAP LOCK 其实是锁的属性,另外我们知道 InnoDB 常规锁模式有:S 和 X,即共享锁和排他锁.锁模式和锁属性是可以随意组合的,组合之后的冲突矩阵如下,这对我们分析死锁很有帮助:

解决一次mysql死锁问题

多线程开启事务处理.每个事务有多个update操作和一个insert操作(都在同一张表).

默认隔离级别:Repeatable Read

逻辑删除原有数据

插入新的数据

根据现有数据情况,update的时候没有数据被更新

报了非常多一样的错

发现居然有死锁.

根据常识考虑,我每个线程(事务)更新的数据都不冲突,为什么会产生死锁?

带着这个问题,打印mysql最近一次的死锁信息

show engine innodb status

显示如下

发现事务1在等待一个锁

关于锁的描述,出现了 lock_mode , gap before rec , insert intention 等字眼,看不懂说明了什么?说明我关于mysql的锁相关的知识储备还不够.那就开始调查mysql的锁相关知识.

通过搜索引擎,

锁的持有兼容程度如下表

那么再回到死锁日志,可以知道 :

事务1正在获取插入意向锁

再看我们上面的锁兼容表格,可以知道, gap lock和insert intention lock是不兼容的

让我回顾一下gap lock的定义:

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

那为什么是gap lock,gap lock到底是基于什么逻辑锁的记录?发现自己相关的知识储备还不够.那就开始调查.

ps:当前索引不是普通索引,而且是唯一索引等其他情况,请参考下面资料

MySQL 加锁处理分析

回到我自己的案例中,重新屡一下事务1的执行过程:

因为普通索引

KEY hotel_date_idx ( hotel_id , rate_date )

这段sql会获取一个insert intention lock (waiting)

这段sql也会获取一个insert intention lock (waiting)

重新梳理一下:

gap lock 导致了并发处理的死锁

在mysql默认的事务隔离级别(repeatable read)下,无法避免这种情况.只能把并发处理改成同步处理.或者从业务层面做处理.

共享锁、排他锁、意向共享、意向排他

record lock、gap lock、next key lock、insert intention lock

MySQL可重复读防止幻读

接上篇 事务隔离级别和幻读 ,留了个坑,没想到竟然过了10天,时间不注意真的过的好快.顺便提下,图片链接是属于网站的,开发自己的图床迫在眉睫,万一哪天迁移就要做很多额外工作,一些概念或者思路用图片表达更直观清楚.

回到正题,之前提到一般情况下MySQL的InnoDB引擎在可重复读的情况下是没法保证不出现幻读的,但实际情况是MySQL可以通过加锁来防止幻读的出现,这种锁定通过Next-key机制来实现,是属于记录锁和间隙锁(Gap锁)的结合.

引申,行级别锁的三种算法:

举个存在唯一索引和辅助索引的例子做说明:

所以呢在另一个事务里执行以下语句都会阻塞,具体分析:

这种锁定情形下,可以执行的包括类似语句:

insert的特殊情况

[1]:<>-第六章:锁

版权声明:倡导尊重与保护知识产权。未经许可,任何人不得复制、转载、或以其他方式使用本站《原创》内容,违者将追究其法律责任。本站文章内容,部分图片来源于网络,如有侵权,请联系我们修改或者删除处理。

编辑推荐

热门文章