mysql锁技术讨论

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介:

mysql 常见锁问题分析

1 参考资料

2 要明确的概念

  • 不可重复读和幻读的区别
  • 快照读和当前读
  • 事务的隔离级别
  • record lock、gap lock、next-key lock

2.1 不可重复读和幻读的区别

select数据的不变性可以细分成2部分

  • 第一部分就是:对原有数据的不可修改性,如update delete,通过行锁锁住记录就可以实现不可修改
  • 另一部分就是:对于新增数据的限制,这时候就不能通过行锁来解决了,这时候就需要通过gap lock来解决

如果仅仅满足了第一部分可以叫可重复读,如果也满足了第二部分就算是解决了幻读的问题。

而目前mysql的innodb数据库引擎实现的Repeatable reads不仅仅解决了上述的第一部分也解决第二部分,即Repeatable reads级别下已经解决了幻读问题。

2.2 快照读和当前读

快照读: 如普通的select * from t where id>=6;采用MVCC(多版本并发控制)仅仅读取该事务号及其之前的数据

当前读:如select * from t where id>=6 for update;读取的是最新提交的事务号及其之前的数据

2.3 事务的隔离级别

Read committed 的隔离级别:只能读到别人已提交的数据,未提交的数据读不到,RC的隔离级别存在不可重复读和幻读的现象,即在同一个事务内,第一次select查询出一定结果后,别的客户端此时又修改了源数据和提交了新的数据,第二次select是可以查出修改后的数据和新提交的数据的,这就导致了和第一次select的数据不一致的问题

Repeatable reads 的隔离级别:比起Read committed,解决了不可重复读的现象,而mysql的innodb数据库引擎实现的Repeatable reads也解决了幻读问题。

  • 对于快照读中的幻读(即select * from t where id>=6出现的幻读)采用的解决方式是采用MVCC(多版本并发控制)
  • 对于当前读中的幻读(即select * from t where id>=6 for update出现的幻读)采用的解决方式是gap lock

3 问题分析

如下的一个事务并发执行

start transaction;
DELETE FROM t WHERE id =6;
INSERT INTO t VALUES(6);
commit;

就隔离级别和id唯一索引、id非唯一索引组合等情况展开分析以下内容:

  • 使用了什么锁?阻塞情况?
  • 是否会出现死锁?

3.1 Read committed和唯一索引id

3.2 Read committed和非唯一索引id

3.3 Repeatable reads和唯一索引id

创建表的sql:

create table m (
    id int ,
    primary key (id)
);

填充数据 1、2、6、8

insert into m values(1),(2),(6),(8);

步骤1:客户端A

start transaction;
delete from m where id =6;

步骤2:客户端B

start transaction;
delete from m where id =6;

步骤3:客户端A

insert into m value(6);

步骤4:客户端B

insert into m value(6);

3.3.1 删除一个已存在的值

其中delete from m where id =6语句会对索引中id=6的记录加上next-key lock,但是由于where id=6的查询条件结果是确定的,即不会出现幻读的情况,所以仅仅对id=6的记录加上一个record lock即可,即由next-key lock降级到了record lock。

所以当客户端A执行完毕步骤1后,客户端B执行步骤2的时候,由于已经存在了record lock,所以客户端B会被阻塞,等待客户端A的record lock的释放,现象如下:

输入图片说明

3.3.2 删除一个不存在的值

上述的id=6全部换成id=5,即客户端A执行delete from m where id=5;由于记录不存在,所以只会在索引(2,6)区间中加上gap lock。此时如果客户端B也同样执行delete from m where id=5,由于记录不存在,也只会在索引(2,6)区间中加上gap lock,这两个gap lock之间不冲突,可以同时存在。

此时客户端执行insert into m value(5),因为insert语句会添加一个 insert intention gap lock(见官方文档insert intention gap lock),其中这个锁和gap lock是可以冲突的,此时插入的数值5刚好在上述客户端B创建的gap lock锁定的区间中,所以此时客户端A是要等待客户端B释放gap lock的,即被阻塞了

此时客户端B同样执行insert into m value(5),也会因为客户端A创建的gap lock而造成阻塞,此时客户端A、B相互阻塞造成死锁,现象如下

输入图片说明

发生死锁后,innode引擎自动检测到死锁,会让一个进行释放,另一个得到执行

3.4 Repeatable reads和非唯一索引id

创建表的sql:

create table t (
    id int ,
    key (id)
);

填充数据 1、2、6、8

insert into t values(1),(2),(6),(8);

步骤1:客户端A

start transaction;
delete from t where id =6;

步骤2:客户端B

start transaction;
delete from t where id =6;

步骤3:客户端A

insert into t value(6);

步骤4:客户端B

insert into t value(6);

3.4.1 删除一个已存在的值

其中delete from t where id =6语句会对索引中id=6的记录加上next-key lock,即id=6的记录本身加上record lock,同时(2,6)、(6,8) 这两个区间会加上gap lock。

所以当客户端A执行完毕步骤1后,客户端B执行步骤2的时候,由于已经存在了record lock,所以客户端B会被阻塞,等待record lock的释放,现象如下:

客户端B被阻塞

3.4.2 删除一个不存在的值

假如上述的id=6全部换成id=5,执行 delete from t where id =5的话,即delete 一个不存在的值,则只会对索引的(2,6)区间加上gap lock。客户端B就不会阻塞,同样的在索引(2,6)区间加上gap lock,gap lock之间不冲突的,即这时的客户端B不会阻塞。

这时客户端A执行 insert into t value(5)会阻塞,因为insert语句会添加一个 insert intention gap lock(见官方文档insert intention gap lock),其中这个锁和gap lock是可以冲突的,此时插入的数值5刚好在上述客户端B创建的gap lock锁定的区间中,所以此时客户端A是要等待客户端B释放gap lock的,即被阻塞了

输入图片说明

而客户端A执行的insert into t value(5)所加入的insert intention gap lock是不会和自己创建的gap lock冲突的,即如果没有其他gap lock的话,客户端A往自己创建的gap lock区间中insert值是不被阻塞的

输入图片说明

假如此时客户端B同样执行insert into t value(5)操作,则会因为客户端A创建的gap lock而等待,此时客户端A B在相互等待对方释放gap lock,造成死锁,现象如下:

输入图片说明

发生死锁后,innode引擎自动检测到死锁,会让一个进行释放,另一个得到执行

4 案例演示当前读和快照读

创建表的sql:

create table t (
    id int ,
    key (id)
);

填充数据 1、2、6、8

insert into t values(1),(2),(6),(8);

步骤1:客户端A

start transaction;
select * from t where id>=6;

步骤2:客户端B

start transaction;
insert into t value(10);
commit;

步骤3:客户端A

select * from t where id>=6;
select * from t where id>=6 for update;

步骤3中是第一个select是看不到客户端B新增的数据的,因为他是快照读,读取的是该事务号及其之前的数据

步骤3中的第二个select是可以看到客户端B新增的数据的,因为它是当前读,读取的是最新提交的事务号及其之前的数据

现象如下:

输入图片说明

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
监控 关系型数据库 MySQL
10亿数据如何最快速插入MySQL:技术干货分享
【8月更文挑战第2天】在大数据时代,处理并快速插入数十亿条数据到MySQL数据库是许多企业面临的关键挑战。本文将深入分享一系列高效的技术策略和实战经验,帮助读者优化这一过程,确保数据能够快速、准确地进入数据库系统。
98 1
|
4天前
|
存储 关系型数据库 MySQL
技术解析:MySQL中取最新一条重复数据的方法
以上提供的两种方法都可以有效地从MySQL数据库中提取每个类别最新的重复数据。选择哪种方法取决于具体的使用场景和MySQL版本。子查询加分组的方法兼容性更好,适用于所有版本的MySQL;而窗口函数方法代码更简洁,执行效率可能更高,但需要MySQL 8.0及以上版本。在实际应用中,应根据数据量大小、查询性能需求以及MySQL版本等因素综合考虑,选择最合适的实现方案。
26 6
|
13天前
|
关系型数据库 MySQL 数据库
Mysql的锁
本文介绍了MySQL中表级锁和行级锁的区别,其中MyISAM仅支持表级锁,而InnoDB支持表级锁和行级锁,默认为行级锁。表级锁锁定整个表,实现简单,资源消耗少,但并发度低;行级锁仅锁定相关记录,减少冲突,提高并发度,但加锁开销大。此外,还介绍了共享锁和排他锁的概念及意向锁的作用。
|
29天前
|
监控 关系型数据库 MySQL
在Linux中,mysql的innodb如何定位锁问题?
在Linux中,mysql的innodb如何定位锁问题?
|
8天前
|
SQL 关系型数据库 MySQL
MySQL技术安装配置、数据库与表的设计、数据操作解析
MySQL,作为最流行的关系型数据库管理系统之一,在WEB应用领域中占据着举足轻重的地位。本文将从MySQL的基本概念、安装配置、数据库与表的设计、数据操作解析,并通过具体的代码示例展示如何在实际项目中应用MySQL。
35 0
|
1月前
|
SQL 存储 关系型数据库
mysql加索引真的会锁表吗?揭秘背后的技术细节与规避策略
【8月更文挑战第16天】在数据库管理中,添加索引能大幅提升查询效率。MySQL执行此操作时的锁定行为常引起关注。文章详细解析MySQL中索引添加时的锁定机制及其原理。不同存储引擎及SQL语句影响锁定策略:MyISAM需全表锁定;InnoDB提供更灵活选项,如使用`ALTER TABLE... LOCK=NONE`可在加索引时允许读写访问,尽管可能延长索引构建时间。自MySQL 5.6起,在线DDL技术可进一步减少锁定时间,通过`ALGORITHM=INPLACE`和`LOCK=NONE`实现近乎无锁的表结构变更。合理配置这些选项有助于最小化对业务的影响并保持数据库高效运行。
114 4
|
1月前
|
存储 SQL 关系型数据库
深入MySQL锁机制:原理、死锁解决及Java防范技巧
深入MySQL锁机制:原理、死锁解决及Java防范技巧
|
1月前
|
存储 SQL 关系型数据库
深入解析MySQL事务机制和锁机制
深入解析MySQL事务机制和锁机制
|
1月前
|
SQL 存储 关系型数据库
"MySQL增列必锁表?揭秘InnoDB在线DDL,让你的数据库操作飞一般,性能无忧!"
【8月更文挑战第11天】在数据库领域,MySQL凭借其稳定高效的表现深受开发者喜爱。对于是否会在给数据表添加列时锁表的问题,MySQL的行为受版本、存储引擎等因素影响。从5.6版起,InnoDB支持在线DDL,可在改动表结构时保持表的可访问性,避免长时间锁表。而MyISAM等则需锁表完成操作。例如,在使用InnoDB的表上运行`ALTER TABLE users ADD COLUMN email VARCHAR(255);`时,通常不会完全锁表。虽然在线DDL提高了灵活性,但复杂操作或大表变更仍可能暂时影响性能。因此,进行结构变更前应评估其影响并择机执行。
48 6
|
1月前
|
存储 SQL 关系型数据库
MySQL中的update操作与锁机制
本文探讨MySQL中`UPDATE`操作的自动加锁机制及其对数据一致性的保障作用。尤其在InnoDB存储引擎下,系统会在涉及索引的更新操作中加行锁或间隙锁,防止多事务并发修改同一条记录。通过福利码兑换系统的实例展示,当线程A开启事务更新库存时,线程B试图更新相同记录会被阻塞,直至线程A提交。此外,文章还介绍了乐观锁及版本号控制等策略进一步提升并发性能的方法。作者:小明爱吃火锅,来源:稀土掘金。
115 2

热门文章

最新文章