sql

mysql多线程update死锁问题

2020-03-03  本文已影响0人  雪飘千里

最近想起之前处理过的一个mysql 死锁问题,是在高并发下update批量更新导致的,这里探讨一下发生的原因,以及解决办法;

发生死锁的sql语句如下,其中where条件后的字段是有复合索引的。

update t_push_message_device_history set status=?,update_time=? where msg_id=? and msg_key=? and dev_no=?;

之所以会发生死锁,是与mysql 加锁机制有关系的,下面我们来简单描述下加锁过程;

1. mysql锁介绍

当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。

行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。

虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。

使用行级锁定的主要是InnoDB存储引擎。

2. mysql InnoDB行锁

InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。
在实际应用中,要特别注意以下几点:

3. mysql InnoDB加锁过程

首先要明确的是,InnoDB是边扫描边加锁的。

因为是边扫描边加锁,这里就存在一个顺序问题,假如线程A对a b c d e五条数据边扫描边加X锁,而同时线程B对 e f g h a五条数据也边扫描边加X锁,明显的,这就会存在一个问题,在线程A对e加锁时,线程B已经对e加锁了,所以线程A会等待线程B释放锁,而线程B对a加锁时,线程A也对a加锁了,所以线程B就会等待线程A释放锁,最终结果是,互相循环等待造成死锁。

4. 解决办法

其实,通过上面的加锁过程,我们很容易就找到解决办法了,那就是where后面条件是主键索引,或者是唯一索引,唯一索引或者主键索引不会出现这种问题,是因为每次都只有一条数据,线程A加锁后,线程B等待即可。

上一篇 下一篇

猜你喜欢

热点阅读