关于生产PRD死锁问题的定位

数据库级别死锁

时隔两年,确实有点忘了,deadlock这个问题很常见吧。
大家首先来想一下什么情况下会死锁,最简单的 T1 需要A锁和B锁, T2需要B锁和A锁, T1持有A锁,而T2 持有B锁,此时就造成了比较简单死锁情况。
下面展示一些 内联代码片

public class Hello {

	/**
	 * @param args
	 */
	static Lock lock1 = new ReentrantLock();
	static Lock lock2 = new ReentrantLock();
	public static void main(String[] args) {
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				lock1.lock();
				System.out.println("t1 获取锁lock1 成功");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				lock2.lock();
				System.out.println("t1 获取锁lock2 成功");
				lock2.unlock();
				lock1.unlock();
			}
		});

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				lock2.lock();
				System.out.println("t2 获取锁lock2 成功");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				lock1.lock();
				System.out.println("t2 获取锁lock1 成功");
				lock1.unlock();
				lock2.unlock();
			}
		});
		t1.start();
		t2.start();

	}

然后我们看一下运行结果:在这里插入图片描述很明显代码还在运行,但是卡死了,既T1拿着lock1,等待lock2, T2拿着lock2 等待Lock1.

生产现象1

博主本人在生产中遇到的死锁问题呢是这样的。我尽量简短:
首先我们生产数据库用的是mysql,默认引擎是innoDB,行级锁,毕竟是电商系统,表级锁可能不太适合(关于mysql另外一个博客详解),然后呢 由于代码陈旧,我们的消息处理是用消息中间件MQ,就出现了这样一个问题,比如我t1 在一个事务里 处理 ABC三张表的数据,t2呢也处理这三张表,但是顺序不一致,是CBA,也就是t1 需要拿到A锁、B锁、C锁,t2需要拿到C锁、B锁、A锁, 所以当如果同一单的两条消息同时处理的时候(MQ,不保证消息的顺序性,不是单消费者的话),那么就有可能出现上述死锁情况。

解决方案

那当时我们的解决方案其实很简单,但是属于补洞的行为。并不是从源头上去解决的,源头呢 可能是消息队列 消息积压,导致消费不及时,或者消息来源间隔太短,比如电子书商品,下单和发货消息可能就是在同时的。
那我的解决方案是,将表的处理顺序按字母的自然排序来集中处理,也就是先把要处理的表,放到一个集合里,然后将这些表做一个排序,可能会有人问,如果 我处理是这样的, A B B C,先把B行的状态改为1,然后改为2,这样会不会造成数据错误,这个我已经试过了 ,排序的时候同表的顺序不会打乱,所以是可以解决这个问题的,既所有的处理顺序ABC, 也就不会存在MYSQL 行级锁死锁的问题。

生产场景2

接下来将的是mysql主键锁的问题,首先普及一个知识,MYSQL 大家都知道的,默认搜索引擎是InnoDB,然后该搜索引擎支持行锁,然后mysql数据结构采用B+树。
问:如何唯一确定一条数据?
答:通过主键。一般我们都会给表定义一个主键吧(不定义的出门右转)
问:所以那mysql是如何给一条数据加锁的呢?
答:通过给索引加锁。
情景:table user_item(
id ,
user_id,
item_id.
status,
id PK,
index(user_id,item_id,status)
)
两个索引,一个主键id,还有一个联合索引,没问题吧,
update user_item set status =1 where user_id=? and item_id =?
怎么锁?先锁定联合索引 index,然后锁定PK 。
那如果现在还有一条更新语句,
update user_item set status =0 where id = ? and user id = ?
先锁定PK 再锁联合 。所以矛盾产生了,所以这边建议有这种更新的可以先查询主键 然后根据主键去更新。

服务器级别死锁

没遇见过 可还行?

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值