SQL死锁

目录

前言:

分析:

死锁产生的原因:

sql死锁

模拟:

解决办法: (本质:快速筛选或高效处理、以此减少锁冲突)

①大事务拆成小事务,尽可能缩小事务范围

大事务:将多个操作放在一个事务中执行

小事务:将多个操作分成多个小事务,

 ②业务中存在更新前和更新后一模一样的不再执行更新

3、 调整表修改的顺序

4. 索引不当导致的死锁

为什么建索引能有效避免死锁呢?

5、降低并发 

6、重试机制


前言:

使用脚本刷数据时,开多线程经常遇到死锁现象,面试也经常问到,故开此篇

日志错误示例:

### Error updating database.  Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
### The error may exist in com/patpat/product/mapper/SaleProductSkuMapper.java (best guess)
### The error may involve com.patpat.product.mapper.SaleProductSkuMapper.updateById-Inline
### The error occurred while setting parameters
### SQL: UPDATE ps_sale_product_sku_XXXXX_30002  SET sku_id=?, product_id=?,    sku_code=?, image=?  WHERE id=?
### Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
; Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transactionat org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:271)at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(Abs

分析:

死锁产生的原因:

①不可剥夺(只能由占有资源的进程释放)

②循环等待(每个进程在等待其他进程释放,而其他进程也在等待)

③互斥条件 (一个资源只能同时被一个进程使用)

④请求与保持(申请新资源,并还不释放已占有的)

sql死锁

死锁发生的主要原因是这两个事务对表的锁定顺序不一致,先拿到一把锁的事务等待另一把锁,而那一把锁正被另一个事务持有,形成闭环等待。

模拟:

当多个事务同时访问数据库中的数据并且存在竞争条件时,就有可能发生死锁。下面是一个示例,展示了一个可能导致死锁的情况:

假设有两个用户,用户A和用户B,同时执行以下两个事务:

事务1(用户A):

BEGIN TRANSACTION;
UPDATE orders SET status = 'processing' WHERE order_id = 1;
UPDATE products SET stock = stock - 1 WHERE product_id = 1;
COMMIT;

事务2(用户B):

BEGIN TRANSACTION;
UPDATE products SET stock = stock - 1 WHERE product_id = 1;
UPDATE orders SET status = 'processing' WHERE order_id = 1;
COMMIT;

在以上操作中,存在:用户A执行自己的第一条sql,用户B执行自己第一条sql。用户A再准备执行自己的第二条时,却不能执行了,用户B也不能再执行,于是陷入死锁。如下图:

 死锁产生!

(注意总结 此处死锁的特点:① 开启了事务②交叉修改(如果按顺序操作是不是就不会死锁了呢?应该是的))

那么,死锁是2个以上的不同表才能出现死锁吗?不一定

如下:

事务1:
updae  A  set ... where id =1;
updae  A  set ... where id =2;
..事务2:
update A  set ... where id =2;
update A  set ... where id =1;

因此可以总结:

①同一个表中:在一个事务中对同一表进行两次或多次操作,并且在多线程的情况下有多个这样的事务,这可能会导致死锁。

②不同表中:两个事务操作表的顺序不同,出现锁表交叉循环,导致死锁。

解决办法: (本质:快速筛选高效处理、以此减少锁冲突)

①大事务拆成小事务,尽可能缩小事务范围

大事务:将多个操作放在一个事务中执行

优点:这样可以减少事务的提交和回滚次数,提高性能。

缺点:如果事务过大,涉及到的数据量多,会增加事务持有锁的时间,增加死锁的风险。

小事务:将多个操作分成多个小事务,

优点:每个小事务只涉及少量的数据,尽快释放锁资源。这样可以减少事务持有锁的时间,降低死锁的风险

 ②业务中存在更新前和更新后一模一样的不再执行更新

场景:通过运维拉去mysql日志,查询发现,下面2事务,对表ps_option_value666进行更新操作,查询数据库发现,要更新的数据和想更新的数据,一模一样!

解决方案:在代码层面检查对象内容如果一样,就不更新了!

数据库死锁日志中部分日志:

数据库原有数据:

 数据库死锁日志:

2023-06-15 01:35:18 0x2b170f8877002023-06-15 01:35:18 0x2b170f887700
*** (1) TRANSACTION:
TRANSACTION 15159595386, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 5 row lock(s)
MySQL thread id 506546, OS thread handle 47376231835392, query id 4253348818 172.31.19.109 app_product_0 updating
UPDATE ps_option_value666  SET option_id=6,
value='18-24 Months'  WHERE id=1118
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1236 page no 10 n bits 0 index PRIMARY of table `product_service`.`ps_option_value666` trx id 15159595386 lock_mode X locks rec but not gap waiting
Record lock, heap no 224 PHYSICAL RECORD: n_fields 11; compact format; info bits 00: len=4; bufptr=0x2b231cfcf469; hex= 0000045e; asc    ^;;1: len=6; bufptr=0x2b231cfcf46d; hex= 00000027a645; asc    ' E;;2: len=7; bufptr=0x2b231cfcf473; hex= 940000030237da; asc      7 ;;3: len=4; bufptr=0x2b231cfcf47a; hex= 00000000; asc     ;;4: len=4; bufptr=0x2b231cfcf47e; hex= 00000006; asc     ;;5: len=12; bufptr=0x2b231cfcf482; hex= 31382d3234204d6f6e746873; asc 18-24 Months;;6: SQL NULL;7: len=8; bufptr=0x2b231cfcf48e; hex= 0000000000001840; asc        @;;8: len=4; bufptr=0x2b231cfcf496; hex= 5b061db0; asc [   ;;9: len=4; bufptr=0x2b231cfcf49a; hex= 5f6df00d; asc _m  ;;10: len=0; bufptr=0x2b231cfcf49e; hex= ; asc ;;*** (2) TRANSACTION:
TRANSACTION 15159595381, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 6 row lock(s)
MySQL thread id 506549, OS thread handle 47373393610496, query id 4253348825 172.31.45.125 app_product_0 updating
UPDATE ps_option_value666  SET option_id=6,
value='4-5 Years'  WHERE id=1446
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 1236 page no 10 n bits 0 index PRIMARY of table `product_service`.`ps_option_value666` trx id 15159595381 lock_mode X locks rec but not gap
Record lock, heap no 226 PHYSICAL RECORD: n_fields 11; compact format; info bits 00: len=4; bufptr=0x2b231cfcf4e0; hex= 00000460; asc    `;;1: len=6; bufptr=0x2b231cfcf4e4; hex= 00000027a645; asc    ' E;;2: len=7; bufptr=0x2b231cfcf4ea; hex= 940000030237f6; asc      7 ;;3: len=4; bufptr=0x2b231cfcf4f1; hex= 00000000; asc     ;;4: len=4; bufptr=0x2b231cfcf4f5; hex= 00000006; asc     ;;5: len=9; bufptr=0x2b231cfcf4f9; hex= 352d36205965617273; asc 5-6 Years;;6: SQL NULL;7: len=8; bufptr=0x2b231cfcf502; hex= 0000000000002440; asc       $@;;8: len=4; bufptr=0x2b231cfcf50a; hex= 5b061dbf; asc [   ;;9: len=4; bufptr=0x2b231cfcf50e; hex= 5f6df00d; asc _m  ;;10: len=0; bufptr=0x2b231cfcf512; hex= ; asc ;;[bitmap of 256 bytes in hex: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1236 page no 12 n bits 0 index PRIMARY of table `product_service`.`ps_option_value666` trx id 15159595381 lock_mode X locks rec but not gap waiting
Record lock, heap no 66 PHYSICAL RECORD: n_fields 11; compact format; info bits 00: len=4; bufptr=0x2b231cf95154; hex= 000005a6; asc     ;;1: len=6; bufptr=0x2b231cf95158; hex= 00000027a645; asc    ' E;;2: len=7; bufptr=0x2b231cf9515e; hex= 940000030a0a02; asc        ;;3: len=4; bufptr=0x2b231cf95165; hex= 00000000; asc     ;;4: len=4; bufptr=0x2b231cf95169; hex= 00000006; asc     ;;5: len=9; bufptr=0x2b231cf9516d; hex= 342d35205965617273; asc 4-5 Years;;6: SQL NULL;7: len=8; bufptr=0x2b231cf95176; hex= 0000000000002240; asc       "@;;8: len=4; bufptr=0x2b231cf9517e; hex= 5b061fd6; asc [   ;;9: len=4; bufptr=0x2b231cf95182; hex= 5f6df00d; asc _m  ;;10: len=0; bufptr=0x2b231cf95186; hex= ; asc ;;*** WE ROLL BACK TRANSACTION (2)

3、 调整表修改的顺序

按照同一顺序获取多个锁,释放锁时反序释放。这可以避免不同事务交叉锁定导致死锁。

场景:项目中有以下3个脚本,分别:

事务1控制的脚本:

出现交叉,且在两个事务中循环。如果业务允许,则

4. 索引不当导致的死锁

为什么建索引能有效避免死锁呢?

1.为了减少事务持有锁的时间,以此来降低死锁的可能性。

2、避免不同事务对相同的数据行进行锁定,从而减少锁竞争与死锁。(如:对username字段创建普通索引,对email字段创建唯一索引)

5、降低并发 

如果性能允许,自然是单个线程,相当于单个事务在执行,那肯定没死锁!这个就看代码性能和业务允许不允许了

6、重试机制

如果发生死锁,重试可能就好了哇 

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

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

相关文章

SpringBoot - 在IDEA中经常发现:Could not autowire. No beans of ‘xxx‘ type found的错误

错误描述 在SPRINGBOOT的项目中,使用IDEA时经常会遇到Could not autowire. No beans of ‘xxxx’ type found的错误提示,但是程序的编译和运行都没有问题,这个错误提示并不影响项目的生产。 解决方案

Vue中如何进行状态持久化(LocalStorage、SessionStorage)

Vue中如何进行状态持久化(LocalStorage、SessionStorage)? 在Vue应用中,通常需要将一些状态进行持久化,以便在用户关闭浏览器或刷新页面后,仍能保留之前的状态。常见的持久化方式包括LocalStorage和Sessio…

深入理解 Golang: Channel 管道

Channel 的使用 Channel 声明方法 chInt : make(chan int) // unbuffered channel 非缓冲通道chInt : make(chan int, 0) // unbuffered channel 非缓冲通道chInt : make(chan int, 2) // bufferd channel 缓冲通道 Channel 基本用法 ch <- x // channel 接收数据 xx &l…

(免费分享)springboot,vue扫码点餐

系统前台客户端部署在微信小程序&#xff0c;主要面向的对象为到店点餐用户&#xff0c;我们要为买家提供一套完整的网上购物服务&#xff0c;内容包括扫码点餐、支付下单、凭取餐码取餐等。 系统后台客户端使用H5端&#xff0c;面向对象为在职员工&#xff0c;为员工提供各种…

7/2~7/4学习成果总结

这几天初步的了解了一下Java&#xff0c;然后写了几道题&#xff1a; 下面总结一下学Java的时候遇到的一易错的小问题以及总结&#xff1a; 1. java里面只能在一个源文件里有一个public类&#xff0c;但是入口main那个可以理解为public static是一个整体也就是不属于public&a…

2023 全球数字经济大会人工智能高峰论坛,和鲸科技入选北京市人工智能行业赋能典型案例

7月&#xff0c;由国家发展改革委、工业和信息化部、科技部、国家网信办、商务部、中国科协联合北京市人民政府共同主办“2023全球数字经济大会”在京召开&#xff0c;本届活动主题为“数据驱动发展&#xff0c;智能引领未来”。其中“人工智能高峰论坛”重点围绕通用人工智能大…

【雕爷学编程】Arduino动手做(150)---旋转角度传感器模块

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

图神经网络:(图像分割)3D人物图像分割

文章说明&#xff1a; 1)参考资料&#xff1a;PYG的文档。超链。斯坦福大学的机器学习课程。超链。(应该要挂梯子)。博客原文。超链。(应该要挂梯子)。原文理论参考文献。超链。提取码8848。 2)我在百度网盘上传这篇文章jupyter notebook和预训练模型。超链。提取码8848. 3)博主…

【Spring Boot】Spring Boot配置文件详情

前言 Spring Boot是一个开源的Java框架&#xff0c;用于快速构建应用程序和微服务。它基于Spring Framework&#xff0c;通过自动化配置和约定优于配置的方式&#xff0c;使开发人员可以更快地启动和运行应用程序。Spring Boot提供了许多开箱即用的功能和插件&#xff0c;包括嵌…

微信小程序 滚动到底部加载新的数据 之后滚动到顶部

1.配置到底部监听 在app.json的window里面加入 里面的300表示距离底部300rpx触发onReachBottom事件 默认50rpx "window": {"onReachBottomDistance": 300}, 2.在数据列表的js页面 /*** 页面上拉触底事件的处理函数*/onReachBottom() {console.log("…

消息中间件面试题详解

RabbitMQ 如何保证消息不丢失 消息的重复消费问题如何解决 rabbitmq中死信交换机&#xff08;RabbitMQ延迟队列有了解吗&#xff09; 延迟队列&#xff1a;进入队列的消息会被延迟消费的队列 场景&#xff1a;超时订单&#xff0c;限时优惠&#xff0c;定时发布 延迟队列 …

【Linux】-第一个小程序(进度条)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树 &#x1f389;作者宣言&#xff1a;认真写好每一篇博客 &#x1f38a;作者gitee:gitee &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作…