mysql锁表问题

问题描述

偶尔应用日志会打印锁表超时回滚

org.springframework.dao.CannotAcquireLockException: 
### Error updating database.  Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

mysql锁机制

锁的划分

按粒度划分

按照锁的粒度来划分可以将锁分为以下三种:

  • 全局锁:锁的整个database。由MySQL的SQLlayer层实现

  • 表级锁:锁的是某个table。由MySQL的SQLLayer层实现

  • 行级锁:锁的是某行数据,也可能锁定行之间的间隙。由存储引擎实现,比如InnoDB等

按锁的功能划分

根据锁的功能可以将锁分为:

  • 共享读锁

  • 排他写锁

按锁的实现方式划分

根据锁的实现方式可以将锁分为:

  • 悲观锁

  • 乐观锁

表级锁和行及锁的区别
  • 表级锁:开销小,加锁快,锁定粒度大,发生锁冲突概率高,并发度低

  • 行级锁:开销大,加锁慢,会出现死锁,锁定粒度小,发生锁冲突概率低,并发度高

表级锁

mysql表级锁分为两种:

  • 表锁

  • 元数据锁

表锁

查看表锁的争用状态变量

show status like 'table%';

在这里插入图片描述

  • Table_locks_immediate:产生表级锁定的次数

  • Table_locks_waited:出现表级锁定争用而发生等待的次数

表锁的两种表现形式:

  • 表共享读锁

  • 表独占写锁

手动添加表锁

lock table 表名 read(共享读锁)/write(独占写锁), 表名n read(共享读锁)/write(独占写锁);

查看表锁情况

show open tables

删除表锁

unlock tables;
演示

创建演示表并插入数据

CREATE TABLE mylock (    
id int(11) NOT NULL AUTO_INCREMENT,    
name varchar(20) DEFAULT NULL,    
age int(11) DEFAULT NULL,    
love varchar(255) DEFAULT NULL,    
PRIMARY KEY (id)    
);INSERT INTO mylock (id,name,age,love) VALUES (1, 'a', 1, 'a');
INSERT INTO mylock (id,name,age,love) VALUES (2, 'b', 1, 'b');
INSERT INTO mylock (id,name,age,love) VALUES (3, 'c', 1, 'c');

读锁操作:

  1. session1:对mylock表添加共享读锁
lock table mylock read;
  1. session1:查询mylock表
select * from mylock;
  1. session2:可正常查询mylock表
select * from mylock;
  1. session1:不能查询其他没有锁定表
select * from 其他没有锁定表的表名称;
  1. session2:可正常查询、更新没有锁定的表
select * from 其他没有锁定表的表名称;
  1. session1:更新、插入锁定表会提示错误
INSERT INTO mylock (id,name,age,love) VALUES(4, 'd', 1, 'd');UPDATE mylock SET NAME = 'e' WHERE id = 3;
  1. session2:更新、插入锁定表会一直等待获得锁。当session1 unlock tables解除锁定后会正常执行
INSERT INTO mylock (id,name,age,love) VALUES(4, 'd', 1, 'd');UPDATE mylock SET NAME = 'e' WHERE id = 3;

写锁操作:

  1. session1:对mylock表添加独占锁
lock table mylock write;
  1. session1:对锁定表执行查询、插入、更新均可行
select * from mylock;insert into mylock(id,name,age,love) values(5, 'e', 1, 'e');update mylock set name = 'f' where id = 4;
  1. session2:对锁定表执行查询、插入、更新会一直等待
select * from mylock;insert into mylock(id, name,age,love) values(5, 'e', 1, 'e');update mylock set name = 'f' where id = 4;
  1. session1:释放锁定表
unlock tables;
  1. seesion2:第3步操作正常结束
元数据锁

从MySQL 5.5开始引入MDL,当对一张表做增删改查操作时,将加MDL读锁;当对表结构做变更操作时,加MDL写锁

  1. session1:开始事务
begin;
  1. session1:执行查询表sql将会加MDL读锁
select * from mylock;
  1. session2:执行更新表结构,将会被阻塞
alert talble mylock add f int;
  1. session1:提交事务,或者rollback回滚事务,释放读锁
commit;
  1. session2:第3步的更新表结构将会被执行

行级锁

mysql行级锁的实现是由存储引擎实现,InnoDB存储引擎就支持行级锁。InnoDB行锁是给索引上的索引项加锁来实现,因此只有通过索引条件检索的数据,InnoDB才能使用行级锁,否则将使用表锁

按照锁定范围,将InnoDB的行级锁分为以下三种:

  • 记录锁(Record Locks):锁定某行记录,执行SQL语句的条件必须是主键或唯一索引列,并且必须是精确匹配(=)

  • 间隙锁(Gap Locks):锁定一段区间,此区间内的数据可以已经存在也可能还没有。例如SELECT * FROM table WHERE age > 60 FOR UPDATE; 会
    锁定所有大于60的数据,之后插入一条数据库中没有的age为110的数据一样会被阻塞。间隙锁基于非唯一索引

  • 临键锁(Next-Key Locks):一种特殊的间隙锁。在每个数据行的非唯一索引列上都有一把临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭的区间。例如一张表有age字段,值为10、26、36、46、56的五行数据,age字段为普通索引,这五行数据存在如下范围的临键锁:范围为[负无穷,100)、范围为[10,26)
    、范围为[26,36)、范围为[36,46)、范围为[46,56)、范围为[56,正无穷)。当执行UPDATE table SET name = Vladimir WHERE age = 26;,将
    获取范围为[10,36)的临键锁,之后执行INSERT INTO table VALUES(100, 30, ‘Ezreal’);,将会被阻塞

实验索引对InnoDB行锁的影响
  1. session1:关闭自动提交事务
SET autocommit=0;
  1. session1:执行增、删、改操作中的一种,并且不走索引。将触发表级锁
delete from mylock where name = 'b';insert into mylock(id,name,age,love) VALUES (13, 'm', 1, 'm');update mylock set love = 'b' where name = 'm'
  1. session2:对同一张表执行增、删、改,将被阻塞,等待获取表锁,如果session1不提交事务释放锁,session2会一直被阻塞直到超时
delete from mylock where name = 'h';insert into mylock(id,name,age,love) VALUES (14, 'n', 1, 'n');update mylock set love = 'b' where name = 'h';
  1. session1:提交事务或者回滚,将释放表级锁
commit;
  1. session2:第3步执行操作如果还没有超时,将会执行

为表添加索引字段

ALTER TABLE mylock ADD INDEX mylock_index_1 (name,love);

执行如下操作步骤:

  1. session1:执行增、删、改操作中的一种,并且走索引。将触发表行级锁
delete from mylock where name = 'c';insert into mylock(id,name,age,love) VALUES (13, 'm', 1, 'm');update mylock set love = 'h' where name = 'm'
  1. session2:执行执行增、删、改操作中的一种,如果操作的行不在第一步锁定的行中,将能正常执行
delete from mylock where name = 'l';insert into mylock(id,name,age,love) VALUES (16, 'o', 1, 'o');update mylock set love = 'h' where name = 'c'
临键锁实验

前提数据如下age为普通索引字段
在这里插入图片描述

  1. session1:关闭自动提交事务
SET autocommit=0;
  1. session1:根据普通索引删除数据触发临键锁,锁定范围为[2, 9)
delete from mylock where age = 5;
  1. session2:关闭自动提交事务
SET autocommit=0;
  1. session2:插入[2, 9)之间的age数据将会被阻塞等待获取锁,之外的数据可以正常插入
insert into mylock(id,name,age,love) VALUES (34, 'm', 8, 'ddm');
commit

注意:删除表数据时,如果条件中出现不在索引中字段时,可能不会走索引,因此设置索引字段时需要注意

总结:当存在没有走索引的增、删、改将触发表级锁,如果此事务花费时间较长,可能导致其他事务对表的增、删、改被阻塞,甚至超时回滚。因此合理设置索引字段很重要

解决方案

在了解了mysql锁相关知识后,我们可以根据锁产生的条件,找到超时的原因

如何查看锁及被锁住的SQL

INNODB_TRX

此表记录了当前运行的所有事务

SELECT * FROM information_schema.INNODB_TRX;
INNODB_LOCKs

此表记录了当前出现的锁

SELECT * FROM information_schema.INNODB_LOCKs;
INNODB_LOCK_waits

此表记录了锁等待的对应关系

SELECT * FROM information_schema.INNODB_LOCK_waits;
查询锁住的SQL及事务Id及事务线程Id
select a.trx_id 事务id ,a.trx_mysql_thread_id 事务线程id,a.trx_query 事务sql 
from INFORMATION_SCHEMA.INNODB_LOCKS b,INFORMATION_SCHEMA.innodb_trx a 
where b.lock_trx_id=a.trx_id;
死锁处理

如果出现死锁临时解决方案可以在mysql会话中执行如下命令

kill 事务线程id;

解决方案一:检查索引

查看锁住的SQL,检查被锁表结构是否包含索引,由于行锁需要走索引,如果表不包含索引,将会走表锁,也就是说如果某个事务对表执行删除、更新、新增操作将锁住整张表,如果这时有另一个事务要执行删除、更新、新增操作将会被阻塞。当前一个事务比较耗时,后面事务很有可能超时

检查表索引设置是否正常,只有执行删除、更新、新增操作的SQL走索引才能触发行锁,否则将使用表锁。因此正确设置索引也很重要。尤其在删除操作时,如果条件只包含部分索引字段很有可能不会走索引,具体会不会走索引可以查看SQL执行计划

EXPLAIN 执行的SQL语句;

重点关注type字段,常见类型有:

  • system:表只有一行记录,const类型的特例

  • const:通过主键索引或唯一索引一次就找到,只匹配一行数据

  • eq_ref:主键或唯一索引扫描,对于每个索引键表中只有一条记录与之匹配

  • ref:使用非唯一索引进行查找,可以包含不在索引中的字段。可能返回多行匹配数据,但如果查询数据量占总数据的比列过高将会变为ALL

  • range:根据索引检索给定范围数据,一般条件中出现between、<、>、in等

  • index:索引扫描,与ALL区别是index只遍历索引数

  • ALL:全表扫描

key_len:表示索引中使用的字节数,查询中使用的索引的最大可能长度,并非实际使用长度,理论上长度越短越好

解决方案二:检查超时时间是否合理

运行如下命令获取当前mysql设置的锁等待超时时间(默认50秒)

SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';

根据自己业务确定最佳超时时间,设置过小可能会导致很多事务超时取消。过大可能会导致很多无法完成的死锁事务积压,影响到数据库的并发处理能力。设置锁等待超时方式如下

  • 设置当前session锁等待超时时间
set innodb_lock_wait_timeout=1500;
  • 设置全局锁等待超时时间,对于修改之后新打开的session生效
set GLOBAL innodb_lock_wait_timeout=1500;

解决方案三:检查长事务是否合理

长事务中锁定表数据较长,可能会导致其他事务操作同一条数据时超时。通常建议将事务的粒度做的尽量小,避免长事务,这样系统的并发度、处理效率都会高很多,而且锁超时的现象也会少很多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/787973.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue-ueditor-wrap上传图片报错:后端配置项没有正常加载,上传插件不能正常使用

如图所示,今天接收一个项目其中富文本编辑器报错 此项目为vue2项目,富文本编辑器为直接下载好的资源存放在public目录下的 经过排查发现报错的函数在ueditor.all.min.js文件内,但是ueditor.all.min.js文件夹是经过压缩的 所以直接,将index.html中的引用路径修改为ueditor…

商城网站-礼品网站首页html+css+js+说明文档

网页设计与网站建设作业htmlcssjs 预览 说明 单页面&#xff0c;轮播图 获取&#xff1a;https://hpc.baicaitang.cn/2077.html

java的警示之有危险的行为

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;&#x1f468;&#x1f3fb;‍&#x1f393;告别&#xff0c;今天 &#x1f4d4;高质量专栏 &#xff1a;☕java趣味之旅 欢迎&#x1f64f;点赞&#x1f5e3;️评论&#x1f4e5;收藏&#x1f493;关注 &#x1f496;衷心的希…

06 | Swoole 源码分析之 Coroutine 协程模块

首发原文链接&#xff1a;Swoole 源码分析之 Coroutine 协程模块 大家好&#xff0c;我是码农先森。 引言 协程又称轻量级线程&#xff0c;但与线程不同的是&#xff1b;协程是用户级线程&#xff0c;不需要操作系统参与。由用户显式控制&#xff0c;可以在需要的时候挂起、或…

Redis中的复制功能(三)

复制 服务器运行ID 除了复制偏移量和复制积压缓冲区之外&#xff0c;实现部分重同步还需要用到服务器运行ID(run ID): 1.每隔Redis服务器&#xff0c;不论主服务器还是从服务&#xff0c;都会有自己的运行ID2.运行ID在服务器启动时自动生成&#xff0c;由40个随机的十六进制…

迈向数字化医疗:互联网医院APP开发中的设计思路与技术要点

在开发互联网医院APP时&#xff0c;需要综合考虑设计思路和技术要点&#xff0c;确保用户体验和医疗服务质量的提升。接下来&#xff0c;小编将从设计思路和技术要点两个方面进行讲解。 一、设计思路 用户导向&#xff1a;在设计互联网医院APP时&#xff0c;需要将用户体验放在…

RocketMQ 消费者源码解读:消费过程、负载原理、顺序消费原理

B站学习地址 上一遍学习了三种常见队列的消费原理&#xff0c;本次我们来从源码的角度来证明上篇中的理论。 1、准备 RocketMQ 版本 <!-- RocketMQ --> <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-s…

vs2022断点找bug出错(打上100个断点)

初步分析&#xff1a;故障出自-具体功能模块 进一步分析&#xff1a;故障出自-该功能代码流程 进一步分析&#xff1a;从该功能起点-终点&#xff0c;一路打100个断点

ICLR 2024 | 鸡生蛋蛋生鸡?再论生成数据能否帮助模型训练

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了人工智能中文站https://ai.weoknow.com 每天给大家更新可用的国内可用chatGPT资源 发布在https://it.weoknow.com 更多资源欢迎关注 随着生成模型&#xff08;如 ChatGPT、扩散模型&#xff09;飞速发展&#x…

Nomad Web更新没有最快只有更快

大家好&#xff0c;才是真的好。 很长时间没介绍运行在浏览器中的Notes客户端即Nomad Web更新情况。 不用安装&#xff0c;直接使用&#xff0c;还可以完美地兼容适应各种操作系统&#xff0c;Nomad Web一定是Notes/Domino产品现在和将来重点发展的用户访问模式。 不过&…

【CKA模拟题】一文教你用StorageClass轻松创建PV

题干 For this question, please set this context (In exam, diff cluster name) kubectl config use-context kubernetes-adminkubernetesYour task involves setting up storage components in a Kubernetes cluster. Follow these steps: Step 1: Create a Storage Class…

书生 浦语 大模型趣味 Demo

目录 一. 部署 InternLM2-Chat-1.8B 模型进行智能对话 1. 环境准备 2. 下载模型参数 3. 运行Demo 二. 部署实战营 八戒-Chat-1.8B 模型 1. 下载Demo仓库 2. 启动web服务端加载八戒模型&#xff1a; 3. 将SSH远程端口映射到本地 4. 在本地浏览器打开&#xff1a;http:/…

Python抓取抖音直播间数据:技术探索与实践

目录 一、引言 二、技术准备 三、分析抖音直播间网页结构 四、编写爬虫代码 五、处理反爬虫机制 六、数据清洗与存储 七、总结 一、引言 随着互联网的快速发展&#xff0c;直播行业已成为当下的热门领域。抖音作为其中的佼佼者&#xff0c;吸引了大量的用户和主播。对于…

元宇宙虚拟空间的场景构造(二)

前言 该文章主要讲元宇宙虚拟空间的场景构造&#xff0c;基本核心技术点&#xff0c;不多说&#xff0c;直接引入正题。 场景的构造 使用引入的天空模块 this.sky new Sky(this); 在Sky模块里&#xff0c;有设置对其中的阳光进行不同时间段的光线处理。而天空又是怎么样的…

STM32 DWT数据观察触发器作为延时函数的使用

STM32 DWT数据观察触发器作为延时函数的使用 &#x1f4d1;DWT(Data Watchpoint and Trace数据观察触发器&#xff09;描述 &#x1f4dd;DWT是属于处理器内核单元中的调试组件之一&#xff0c;由四个比较器组成。它们可配置为&#xff1a;硬件监视点或对ETM或PC采样器或数据地…

dcoker 下redis设置密码

修改Docker里面Redis密码 Redis是一个开源的内存数据结构存储系统&#xff0c;常用于缓存、消息队列和数据持久化等场景。在使用Docker部署Redis时&#xff0c;默认情况下是没有设置密码的&#xff0c;这可能会导致安全隐患。因此&#xff0c;为了保证数据的安全性&…

蓝桥杯真题Day44 倒计时10天 练了六道真题 !

[蓝桥杯 2020 省 B2] 平面切分 题目描述 平面上有 N 条直线, 其中第 i 条直线是 yAi​⋅xBi​ 。请计算这些直线将平面分成了几个部分。 输入格式 第一行包含一个整数 N。 以下 N 行, 每行包含两个整数 Ai​,Bi​。 输出格式 一个整数代表答案。 代码表示 #include<…

基于SpringBoot的图书馆管理系统设计与实现

介绍 基于&#xff1a;java8 SpringBoot thymeleaf MySQL8.0.17 mybatis-plus maven Xadmin 实现图书馆管理系统 系统要实现如下的基本管理功能&#xff1a; &#xff08;1&#xff09;用户分为两类&#xff1a;管理员&#xff0c;一般用户。 &#xff08;2&#xff09…

Day57:WEB攻防-SSRF服务端请求Gopher伪协议无回显利用黑白盒挖掘业务功能点

目录 SSRF-原理&挖掘&利用&修复 SSRF无回显解决办法 SSRF漏洞挖掘 SSRF协议利用 http:// &#xff08;常用&#xff09; file:/// &#xff08;常用&#xff09; dict:// &#xff08;常用&#xff09; sftp:// ldap:// tftp:// gopher:// &#xff08;…

群晖NAS使用Docker部署大语言模型Llama 2结合内网穿透实现公网访问本地GPT聊天服务

文章目录 1. 拉取相关的Docker镜像2. 运行Ollama 镜像3. 运行Chatbot Ollama镜像4. 本地访问5. 群晖安装Cpolar6. 配置公网地址7. 公网访问8. 固定公网地址 随着ChatGPT 和open Sora 的热度剧增,大语言模型时代,开启了AI新篇章,大语言模型的应用非常广泛&#xff0c;包括聊天机…