亲身经历的间隙锁问题以及优化过程

作者分享了在一个高并发项目中遇到的间隙锁问题,涉及MySQLDeadlock。通过排查发现,selectforupdate导致间隙锁,优化策略包括使用普通select和更改唯一索引。
摘要由CSDN通过智能技术生成

亲身经历的间隙锁问题

1、问题描述

我负责了一个数据量及并发量比较高的项目,其中有一个对外接口,高峰时并发(tps)在50左右,
这个接口会向一个表a插入1条数据,并在最后更新这条数据的状态,这张表数据量在8000w左右
突然有一天,偶发报错数据库这张表存在deadlock,一天大概出现了3、到5次报错
错误日志:

{index=ylog_9, message=2024-01-09 21:07:03.716||http-nio-8080-exec-4||ERROR||TID:f710574d-0org.springframework.dao.DeadlockLoserDataAccessException: 
### 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/FnaaaDao.java (best guess) ### The error may involve com.insertSelective-Inline
### The error occurred while setting parameters ### SQL: INSERT INTO table1  ( ............t ) VALUES( ?,?,?,?,?,........?,?,?,?,? ) ### 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 transaction
	at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:267)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:88)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:440)
	at com.sun.proxy.$Proxy172.insert(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:271)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62)

2、排查过程

首先介绍一下表table1的结构
id(int) — 自增主键
a (varchar) — 普通索引,但是每一个值在表里面是唯一的
c (varchar) — 普通索引,数据有重复的情况

经过查看代码,这个接口里面针对表table1数据操作的逻辑如下
1)插入1条数据
2)根据c select for update
3)根据a修改当前数据

3、分析优化

分析:
1)第2步select for update会导致多个间隙锁
2)第3步根据a修改当前数据,当前数据可能是数据库最新的一条数据,虽然a的值在业务上是唯一的,但是还是会导致间隙锁,锁住当前记录和正无穷

优化:
1)分析使用场景后,将其改为普通的select,删除for update
2)将a (varchar) — 普通索引 改为 a (varchar) — 唯一索引索引,唯一索引可以避免这个间隙锁问题

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值