MySQL锁:InnoDB行锁需要避免的坑

EF Core执行原生SQL语句 一般Linq操作就够了,尽量不用写原生SQL;非查询SQL用ExecuteSqlInterpolated ();针对实体的SQL查询用FromSqlInterpolated()。复杂SQL查询用ADO.NET的方式或者Dapper等。 阅读详情

前言

因为新公司工作中MySQL库经常出现查询慢,锁等待,节点挂掉…等一系列问题。导致每个程序员头都很大,一味抱怨“为什么我就查一条数据这么卡”,"我TM加了索引的啊,怎么还怎么慢"…我想默默说的是,大部分MySQL出现锁等待,查询奇慢的情况基本都是因为SQL写的不好(有坑),或者数据表设计的不完善。对,不用想!这些所有的坑很大一部分都是自己造成的。那么是什么原因造成的,大部分只是抱怨,而不去关注MySQL的一些细节问题,比如:MySQL行锁的细节,什么情况下会使用表锁等。所以今天先讨论记录下InnoDB特有的行锁的一些细节,加强认识。

InnoDB不同于MyISAM最大的两个特点就是:一是支持事务,二是支持行锁;毋庸置疑,因为这两个特性大部分都采用InnoDB引擎,其中的支持行锁就是InnoDB适合多并发优势所在,但是行锁的一些细节没有深入理解过的话,可能会造成一定的误解,造成“看似命中索引,走行锁,结果却是表锁,最终导致锁等待情况”。


一、InnoDB行锁的实现方式

通过给索引上的索引项加锁来实现的,也就意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。这一点在实际应用中特别需要注意,不然的话可能导致大量的锁冲突,从而影响引发并发性能。

实验一:对没有索引的加锁,导致表锁

1)准备工作:建tab_no_index表,表中无任何索引,并插入数据

2)Session_1: 我们给id=1的行加上排它锁(for update),由于id没有索引,实际上是表级锁;

3)Session_2:我们给id=2的行加上排它锁(for update),由于id没有索引,所以去申请表级锁,但是却出现了锁等待!原因就是在没有索引的情况下,InnoDB只能使用表锁。

备注:MySQL中的for update 仅适用于InnoDB(因为是只有此引擎才有行级锁),并且必须开启事务,在begin与commit之间才生效。for update是在数据库中上锁用的,可以为数据库中的行上一个排它锁。当一个事务的操作未完成时候,其他事务可以对这行读取但是不能写入或更新,只能等该事务Rollback, Commit, Lost connection…

实验二:对有索引的键值加锁,会对所有涉及到的数据行加锁

1)准备工作:对id建索引如下

2)Session_1:此时id是有索引的,我们对id=1 and name=1的一行加排它锁;

3)Session_2:访问不同于Session_1的id=1, name=5行,但是索引键值是一样的,照样等待锁,锁冲突了。

实验三:多个索引时,不同的事务可以使用不同的索引锁定不同的行,不论什么索引,InnoDB都会使用行锁对数据加锁(对有索引的行数据)。

1)准备工作:对tab_no_index追加name索引:alter table tab_no_index add index name(name);

2)Session_1:开启事务对id=1的行加排它锁,即对name=1与name=5两个数据加锁。

3)Session_2:开启事务对name=2行加锁,因为该数据没有被加锁,索引可以获得锁

4)Session_3:再对name=5的数据进行加锁,由于该数据记录已被Session_1锁定,所以等待获得锁。

注意事项:即便使用了索引,但还是要看MySQL具体对SQL的执行计划,不一定能使用到

如我们对实验三对name='2’进行加锁,误以为name是int类型,本来name是有索引的,但是最后结果导致表锁:

具体请看MySQL的索引情况。

二、间隙锁(Next-Key锁)

当用范围条件而不是相等条件检索数据,并请求共享或者排它锁的时候,InnoDB会给符合条件的已有数据记录的索引项加锁;对于不在范围内的但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个间隙加锁,这就是所谓的间隙锁。

如:select * from where id>100 for update 对id大于100的数据对加锁,但是此时数据中id只有1,2….100,101,不仅对存在的101的记录加锁,还会对大于101不存在的数据的间隙加锁。

此外,对使用相等条件请求给一个不存在的记录加锁,InnoDB也会使用间隙锁,如下:

Session_1:对不存在的id=6的记录加锁

Session_2:插入id=6的记录,也会出现锁等待

三、什么时候使用表锁?

对于InnoDB表,在绝大部分情况下都应该使用行锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由,但在个别情况下也使用表级锁;

1)事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间等待和锁冲突;

2)事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。

使用表锁需要注意几点:

1)使用LOCK TABLES虽然可以给InnoDB加表级锁,表级锁不是InnoDB存储引擎层管理的,而是由其上一层MySQL Server负责的

2)在用LOCK TABLES对InnoDB表加锁时需要注意,要将Autocommit设置为0,否则MySQL不会给表加锁;事务结束前,不要用UNLOCK TABLES释放表锁,因为UNLOCK_TABLES隐含提交事务;COMMIT或ROLLBACK并不能释放用LOCK TABLES加表级锁。

SET AUTOCOMMIT=0;

LOCK TABLES table1 WRITE, table2 READ,...;

[do something....]

COMMIT;

UNLOCK TABLES;

总结:

  • 从设计之初,就应该建立良好的索引机制,避免对关键字段搜索时造成表锁;

  • 避免长时间事务未提交等情况,导致锁冲突,死锁等情况;

  • 不要老是抱怨数据库有问题,应该从自身写的SQL分析出发,学会分析(数据库不行大部分是因为SQL写的有问题,没错,是自身问题);

  • 不要总是觉得这是DBA该做的事,开发者应该学会基本的SQL常识(如MySQL的最左索引,回表,索引覆盖等知识),学会基本的优化步骤。

MyBatis-3写SQL语句的72种技巧 本文列出了MyBatis在编写 SQL 语句时的 72 种技巧,覆盖了从基础的 SQL 查询到高级的动态 SQL、性能优化、批量操作等多个方面。这些技巧将帮助开发者在使用 MyBatis 进行数据库操作时提高代码的灵活性、可维护性和性能。编写更灵活的动态 SQL,减少重复代码;优化查询性能,提高数据库访问效率;更高效地处理复杂的数据库交互,如批量插入、更新和删除操作;更好地使用 MyBatis 提供的缓存机制和事务管理功能。通过实践这些技巧,你将能够更高效地进行数据库操作,并提升应用的性能。 阅读详情

相关推荐

mysql常见sql语句练习 sql练习题

1. Mysql基本语句复习 1.1数据库建库操作 这一章会把基本的mysql语句进行复习 打开Sqlyog,新建一个数据库 1.2建表操作 新建两张学习兴趣班级表:唱歌、跳舞 CREATE TABLE sing( s_num VARCHAR(5) NOT NULL UNIQUE COMMENT '身份证号,这儿为了方便以5位算', s_beginDate DATE COMMENT '入班时间' #指定存储引擎为INNODB(这个在优化的时候会学习) )ENGINE=INNODB DEFAULT CHA

weixin_39160689的博客 8503

mysql怎么减少行锁对性能的影响

mysql怎么减少行锁对性能的影响

妙啊,受益终生的20个写SQL的小细节,这次终于学到了

前言 SQL 语句的优化对于研发人员也是非常重要的,高效的 SQL语句经常会给使一个业务逻辑的接口响应速度变得非常快。每一个好习惯都是一笔财富,本文分SQL后悔药,SQL性能优化,SQL规范优雅三个方向,写SQL语句一些小细节的分享! 另外本人整理了20年面试题大全,包含spring、并发、数据库、Redis、分布式、dubbo、JVM、微服务等方面总结,下图是部分截图,需要的话点这里点这里,暗号优快云。 1. 写完SQL先explain查看执行计划(SQL性能优化) 日常开发写SQL的时候,尽量

banzhuanhu的博客 4520

大白话解释 MySQL InnoDB 行锁机制

我在学习 MySQL 原理时,大部分内容看书、网上的文章都基本能理解,唯独 InnoDB 的行锁,加锁规则看着很多,什么从 Next-key Lock 退化成间隙锁或者记录锁巴拉巴拉的,一旦陷入这些规则内容里,很容易看着看着就晕了。今天写这篇文章的目的是为了分享加锁规则背后的思路,不用特地记这些规则,只需要画出图跟着这种思路就能想出加了哪些锁。那么加锁规则背后的思路是什么呢?或者说这么加锁是为了达到什么目的呢?可以简单用一句话总结:为了避免幻读的出现,并减少加锁影响的范围。那么什么是幻读呢?

m0_57042151的博客 566

SQL Server基础Sql语句复习

1.创建表 create table Course( Cno char(4) primary key not null, --创建主键,非空 Cname char(40) not null, Cpno char(4), Ccredit smallint, primary key(Cno,Cname), --双主键 foreign key(Cpno) references Course(Cno) --外键连接Coures表的(Cno列) ) 2插入语句 --添加数据 select * from St

南 墙 3995

基于ODPS的SQL语句

本博文主要是介绍阿里ODPS(Open Data Processing Service)平台上的SQL语言的入门; (一)基本概念 1.ODPS SQL适用于海量数据(TB级别),实时性要求不高的场合,它的每个作业的准备,提交等阶段要花费较长时间, 因此要求每秒处理几千至数万笔事务的业务是不能用ODPS SQL完成的;ODPS SQL采用的是类似于SQL的语法,可以看作是标准SQL的子集,但不

zakexu的专栏 3万+

mysql中的行锁注意事项

如果操作中没有用到索引,则行锁会被装转为表锁。 mysql!

weixin_46811632的博客 505

SQL学习笔记 | 02 SQL语句结构

SQL学习笔记 | 02 SQL语句结构一、表的导入1、表的命名2、导入步骤3、导入需注意二、标准SQL语法1、语句结构2、数据表的其他关键词3、SQL语句的分类 一、表的导入 1、表的命名 2、导入步骤 双击数据库后,点击导入 字段名行:列名 在第一行 日期排序:选择年月日YMD 月份-int型 价格-decimal型 长度-整个字符串的 比例-小数点后几位 点击下一步后,点击开始,导入成...

weixin_44878159的博客 2849

mysql 悲观锁注意事项

mysql 悲观锁 for update 必须置于事务中才有效,当@Transactional标注的方法执行结束后释放锁,如果外层调用方法也开启事务,那就是等外层方法结束后才释放锁

lqz1993的博客 345

在VC++中构造SQL语句

在VC++中构造SQL语句=======================Author:  至尊宝宝(杭州)Email:  zaodt_ms@hotmail.comDate:  2008-6-8转载请附带以上信息,谢谢!目录:1、简介2、表结构3、写一条SQL语句4、用程序生成上边的SQL语句5、字符数据类型6、在MFC中使用CString类7、结束语1、简介好多朋友在构造SQL

至尊宝宝 的专栏 1万+

SQL语句的使用

介绍SQL通用语法及其分类以及SQL语句中DDL,DML,DQL,DCL的详细使用

SHUA_y的博客 1836

Mysql锁注意事项

Mysql锁注意事项

zhongyangjian的专栏 509

常用SQL语句

*创建表时,需要设计表中字段,包含字段名称,例如:id,字段类型,例如:int,varchar,是 否可空,以及是否为主键,是否有默认值,是否自增字段等*//*假定students表只有学生的名字,年龄,年纪信息,学生成绩保存在另一张表studentscore 中,需要查学生的语文,数学,英语成绩*//*方式五,按照指定条件查找指定表的数据,例如查找初二的学生名单*//*创建数据库表时,需要指定在哪个数据库中创建表,有两种方式*//*查看数据,可看到新插入的数据*/

moyu23456的博客 1339

Transact -SQL 语句

Transact- SQL概述了解 SQL 结构化查询语言 Transact-SQL语言是SQL 的增强版本 种类 数据 定义 操纵 控制 常用 事务管理 流程控制 附加的语言元素 常量与变量常量 常量指具体的值,不需要声明 变量分类 全局 局部 局部变量声明 格式 DECLARE {@local_variablep[AS]data_type |@cursor_variable_nameCURS

格物致知,知行合一。 5230

SQL格式化神器:如何写出优雅易读的SQL语句

编写优雅易读的 SQL 语句,能够显著提升团队协作和代码的可维护性。关键点说明缩进和排版规范化缩进和换行,让查询结构更加清晰关键字大小写使用大写字母书写 SQL 关键字逻辑顺序遵循标准的 SQL 语句顺序,保持一致性别名使用别名简化表名和字段名工具和插件使用 SQL 格式化工具提升效率通过这些技巧和工具,你可以在团队中编写出高质量的 SQL 语句,减少潜在的错误,提升代码的可维护性和可读性。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1921

SQL Server中查询CPU占用高的SQL语句

SQL Server中查询CPU占用高的情况,会用到sys.sysprocesses ,dm_exec_sessions ,dm_exec_requests   一、查看当前的数据库用户连接有多少   USE master GO SELECT * FROM sys.[sysprocesses] WHERE [spid]>50 --AND DB_NAME([dbi

李晓蒙的博客 1万+

SQL 语句练习

实验名称 SQL 语句练习 实验地点 实验楼502 实验日期 3.21 一、实验目的及要求 1. 加深对表间关系的理解 2. 理解数据库中数据的查询方法和应用 3. 掌握各种查询的异同及相互之间的转换方法 4. 掌握各种查询要求的实现 二、实验环境 Sql...

weixin_42904113的博客 1867

利用OrthoFinder做泛基因家族聚类分析

这条命令会将 Arabidopsis_thaliana.TAIR10.59_longest_trans.pep.fa 文件中的所有序列ID,去掉ID中的空格后面的部分,只保留 > 后第一个空格之前的基因ID,并将结果保存在 An1.fasta 文件中。muscle 是一种常用的多序列比对工具,用于基因组或蛋白质序列的比对。基因家族(Gene family),是来源于同一个祖先,由一个基因通过基因重复而产生两个或更多的拷贝而构成的一组基因,它们在结构和功能上具有明显的相似性,编码相似的蛋白质产物。

qq_64400864的博客 2755
上一篇: Lambda表达式典型案例,你想要的的都在这儿了!!
下一篇: 一个奇怪的MySQL慢查询,打懵了一群不懂业务的DBA!
Java技术那些事儿
博客等级 码龄5年 2306粉丝 2584原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值