博客
关于我
mysql 死锁(先delete 后insert)日志分析
阅读量:794 次
发布时间:2023-02-10

本文共 1280 字,大约阅读时间需要 4 分钟。

MySQL死锁案例分析及解决方案

背景

在项目中, recently 发生了一次数据库死锁事件。事件发生时,系统尝试将A表和B表的数据合并存储到中间表C中,但C表的aid字段要求唯一性。这意味着每次插入到C表时,都需要首先删除旧的记录以确保唯一性。

为了实现这一功能,开发团队选择在每次插入前执行删除操作。这种方法在高并发场景下表现良好,但由于对MySQL锁机制的不够理解,导致了一次严重的死锁事件。

死锁日志分析

通过执行show engine innodb status命令,获取了最近一次发生的死锁日志。日志显示,两次事务(事务1和事务2)在等待同一颗排他锁,导致死锁。

事务1

  • 事务ID:7427
  • 状态:正在插入,等待锁
  • 等待锁:idx_aid索引的排他锁
  • 锁类型:插入意向锁(X lock

事务2

  • 事务ID:7428
  • 状态:正在插入,等待锁
  • 等待锁:idx_aid索引的排他锁
  • 锁类型:插入意向锁(X lock

锁冲突原因

事务2在执行删除操作时,获得了aid索引的排他锁。随后,事务1和事务2同时尝试插入新的记录,各自请求获取同一颗锁。由于锁已经被事务2占有,事务1被迫等待,但事务2也在等待,双方陷入死锁状态。

通过日志分析可以看出,事务2在等待锁的过程中,事务1也在等待相同的锁。这种双向等待导致了死锁的发生。

解决方法

为了避免类似问题再次发生,可以采取以下措施:

方法一:优化事务设计

将插入操作改为基于id主键的更新操作,这样可以减少对aid索引的争夺。具体做法如下:

DELETE FROM table_c WHERE id = (SELECT id FROM table_c WHERE aid = '目标值');INSERT INTO table_c (aid, bids) VALUES ('目标值', '新值');

这种方法通过先查询id值,再执行删除和插入操作,减少锁冲突的概率。

方法二:调整事务隔离级别

如果业务逻辑无法调整,尝试将事务隔离级别从REPEATABLE Reads调至ReadOnly。这样可以减少锁的竞争程度,但需谨慎评估业务的一致性要求。

方法三:优化索引结构

检查aid索引的结构,确保其为唯一索引。此外,可以考虑使用INNODBFEDERATED引擎或分区技术,以减少锁等待时间。

MySQL死锁经典案例

案例一:当前读S锁与排他X锁的竞争

在高并发系统中,S锁(共享锁)和X锁(排他锁)的混合使用可能导致死锁。例如,一个进程持有S锁,另一个进程试图获取X锁,但由于S锁允许共享,导致等待时间过长。

案例二:非主键索引锁与主键索引锁的竞争

InnoDB中,索引锁的类型包括行锁索引锁。如果一个进程持有索引锁,另一个进程试图获取行锁,这可能导致死锁。特别是在REPEATABLE Reads隔离级别下,索引锁可能阻止行锁的获取。

总结

通过上述案例可以看出,数据库死锁的发生往往与锁机制的不当使用有关。在实际项目中,建议深入学习MySQL的锁机制,合理设计事务和索引策略,避免死锁问题的发生。

转载地址:http://cfbfk.baihongyu.com/

你可能感兴趣的文章
MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
查看>>
MYSQL8.0以上忘记root密码
查看>>
Mysql8.0以上重置初始密码的方法
查看>>
mysql8.0新特性-自增变量的持久化
查看>>
Mysql8.0注意url变更写法
查看>>
Mysql8.0的特性
查看>>
MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
查看>>
MySQL8修改密码的方法
查看>>
Mysql8在Centos上安装后忘记root密码如何重新设置
查看>>
Mysql8在Windows上离线安装时忘记root密码
查看>>
MySQL8找不到my.ini配置文件以及报sql_mode=only_full_group_by解决方案
查看>>
mysql8的安装与卸载
查看>>
MySQL8,体验不一样的安装方式!
查看>>
MySQL: Host '127.0.0.1' is not allowed to connect to this MySQL server
查看>>
Mysql: 对换(替换)两条记录的同一个字段值
查看>>
mysql:Can‘t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘解决方法
查看>>
MYSQL:基础——3N范式的表结构设计
查看>>
MYSQL:基础——触发器
查看>>
Mysql:连接报错“closing inbound before receiving peer‘s close_notify”
查看>>
mysqlbinlog报错unknown variable ‘default-character-set=utf8mb4‘
查看>>