多任务并发锁优化

最近在我们项目中,出现了数据库死锁问题,这里简单记录下分析和解决的过程。

一、原因分析

1.a系统调用c系统的接口进行解析nameList时候,c系统会返回一个taskId,然后在a系统中根据taskId更新fixterm_task_t表。由于接口只允许单个name调用,所以得for循环调用。可能出现20条数据,前10条c系统已经完成了然后给a系统发消息进行后续的步骤。但是a系统还在for循环中进行调用接口执行后10条数据,所以后10条数据的taskId还未更新,还是默认值0。

public void sendTask(List<String> nameList){
	taskSerice.noTxUpdateById(name);
}

2.同时c系统发消息到a系统的消费端接收的时候,在消费消息处理时候会去数据库里面查询出fixterm_task_t这一流程单号所有的数据,然后去对这一批次数据加锁更新数据。加锁的时候是按照name排序加锁的。但是更新的时候,使用的是taskId进行更新,所以存在了在这一批次中还有taskId为0的数据,根据taskId=0,更新的就不止1条了,可能会锁住多行。如果多条消息同时接收到,然后同时锁住taskId=0的行,数据库内可能就会存在锁竞争的情况。

public void handkeMessage(String msg){
	fixTermService.lockAndUpdateTask(msg);
}

public boolean lockAndUpdateTask(TaskResult taskResult){
	// 根据taskResult查询得到taskList
	
	// 排序
	taskDao.sort(Comparator.comparing(TaskResult.getName));
	
	// 锁表 update fixterm_task_t set last_update_date = sysdate where name= #{task.name}
	taskDao.lockTaskList(taskList);
	
	// 更新当前name状态
	int rows = taskDao.updateTaskStatus(TaskResult,"READY");
	// 避免集群情况发生,如果一台机器更新成功,其它机器将更新失败
	if(rows == 0){
		return false;
	}
	
	// 查询当前那么状态,判断一个流程下name的状态是否全部更新完成
} 

二、解决方案

这里在锁表的时候,不能再根据name了,上面已经分析过了会存在死锁问题。由于已经根据taskResult查询得到taskList了且taskList中包含主键id,所以锁表语句根据id进行更新。

-- 锁表 
update fixterm_task_t set last_update_date = sysdate where id= #{task.id}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值