数据库死锁导致rpc服务超时分析

发生背景

服务A和服务B同时对一个表中的同一条记录进行了更新操作

流程如图

代码示例

//服务A
@Transactional
public void serviceAmth{
	System.out.println("服务A事务方法开启");
	//此处更新db_test数据库中table_test表中id=1的记录
	update db_test.table_test set name='hello' where id=1;
	serviceB.serviceBmth()
	System.out.println("服务A事务方法结束");
}

//服务B
@Transactional
public void serviceBmth{
	System.out.println("服务B事务方法开启");
	//此处更新db_test数据库中table_test表中id=1的记录
	update db_test.table_test set name='hello' where id=1;
	System.out.println("服务B事务方法结束");
}

流程分析

当服务A中的方法开启事务,并且更新id=1的记录时,mysql(默认INNODB)数据库会对该行记录上行锁(排它锁),但是此时服务A在提交事务之前调用了服务B中的一个事务方法,需要注意的是,此时服务A中的事务并未提交,所以id=1的记录依旧被锁住,在调用服务B后,该方法也对id=1的记录进行修改,但是此时锁已经被服务A的事务持有,所以只能等待服务A将该锁被释放,线程进入等待,而服务A释放该锁需要等服务B调用完成,所以需要等待服务B结束,结果,两者在互相等待,数据库死锁,导致服务调用超时。

解决方法

将同一行记录的更新放到一个事务中进行。

猜你喜欢

转载自blog.csdn.net/ly853602/article/details/84729398
今日推荐