MySQL 死锁

死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。

1 数据库层面解决死锁的两种方式

1、解决死锁的问题最简单的方式是不要有等待,将任何的等待都转化为回滚,并且事务重新开始。 
这种没有死锁问题的产生。在线上环境中,可能导致并发性能的下降,甚至任何一个事务都不能进行。而这锁带来的问题远比死锁问题更为严重,而这锁带来的问题原题远比死锁问题更为严重,因为这很难被发现并且浪费资源。

2、解决死锁的问题最简单的一种方法时超时,即当两个事务互相等待是,当一个等待时超过设置的某一阈值是,其中一个事务进行回滚,另一个等待的事务就能继续进行。用innodb_lock_wait_timeout用来设置超时的时间。

超时机制虽然简单,仅通过超时后对事务进行回滚的方式来处理,或者说其根据FIFO的顺序选择回滚对象。但若超时的事务所占权重比较大,如事务操作更新很多行(比如某程序猿用死循环来执行一些事务),占用了较多的undo log,这是采用FIFO 的方式,就显得不合适了,因为回滚这个事务的时间相对另一个事务所占用的时间可能会更多。

 

在mysql 5.7.x 和 mysql 5.6.x 对死锁采用的方式: 
mysql 5.6.x 是用锁等待(超时)的方式来解决, 没有自动解决死锁的问题:

 

 

 mysql 5.7.x 默认开启了死锁保护机制:

 

2 死锁演示

如果程序是串行的,那么不可能发生死锁。死锁只存在于并发的情况,而数据库本身就是一个并发运行的程序,因此可能会发生死锁。

死锁示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
a :创建表
create table temp(id int primary key ,name varchar(10));
insert into temp values(1,'a'),(2,'b'),(3,'c');
此时表里只有3条数据
 
执行步骤根据数据顺序来:
1. 事务1:
start transaction;
update temp set name='aa' where id=1;
 
2. 事务2:
start transaction;
update temp set name='bb' where id=2;
 
 
3. 事务1:update temp set name='aaa' where id=2;
   这时候3的步骤会有锁等待, 立马执行4,就会马上产生死锁
4. 事务2: update temp set name='bbb' where id=1;

  

 

3 避免死锁发生的方法

在事务性数据库中,死锁是个经典的问题,但只要发生的频率不高则死锁问题不需要太过担心 
死锁应该非常少发生,若经常发生,则系统是不可用。

查看死锁的方法有两种: 
通过show engine innodb status命令可以查看最后一个死锁的情况 
通过innodb_print_all_deadlocks参数配置可以将所有死锁的信息都打印到MySQL的错误日志中

减少死锁发生的方法: 

1、尽可能的保持事务小型化,减少事务执行的时间可以减少发生影响的概率 
2、及时执行commit或者rollback,来尽快的释放锁 
3、当要访问多个表数据或者要访问相同表的不同行集合时,尽可能的保证每次访问的顺序是相同的。比如可以将多个语句封装在存储过程中,通过调用同一个存储过程的方法可以减少死锁的发生 
4、增加合适的索引以便语句执行所扫描的数据范围足够小 
5、尽可能的少使用锁,比如如果可以承担幻读的情况,则直接使用select语句,而不要使用select…for update语句 
6、如果没有其他更好的选择,则可以通过施加表级锁将事务执行串行化,最大限度的限制死锁发生

posted on   数据与人文  阅读(12)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· RFID实践——.NET IoT程序读取高频RFID卡/标签
历史上的今天:
2021-01-12 expdp 跳过坏块
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

统计

点击右上角即可分享
微信分享提示