基于数据库悲观锁的幂等性控制

分布式环境下,各个服务经常需要互相调用,如何保证调用的任务只被执行一次?本章基于数据的悲观锁,实现了任务的幂等性控制。

幂等性:多次执行所产生的影响均与一次执行的影响相同。比如在一次支付场景中,无论你点击多少次按钮,最终都应该只有一次扣款行为。


1. 根据全局业务流水号businessId查询数据库记录

IdempotentTask taskResult = idempotentTaskMapper.selectByBusinessId(businessId);

2. 判断之前是否有任务存在,如果不存在,本次任务落库。并发情况下也只会有一条写入成功

if (taskResult == null){
	IdempotentTask task = new IdempotentTask();
	task.setBusinessId(businessId);
	task.setCreated(new Date());
	task.setModified(new Date());
	
	//0表示初始化,1表示成功,-1表示失败
	task.setStatus(0);    
	try {
		int result = idempotentTaskMapper.insertTask(task);
		if (result > 0){
		    return true;
		}
	}catch (DuplicateKeyException e){
		LOGGER.error("重复写入任务");
	}catch (Exception e) {
		LOGGER.error("任务写入异常");
	}
	return false;
}

3. 如果上次任务已经存在,判断上次任务的状态。任务已经成功执行或者正在处理中,则拒绝本次任务。如果上次任务执行失败并且业务场景允许失败重试,那么更新任务状态为初始化,重新提交本次任务执行。

if (idempotentTask.getStatus() == 1){
	LOGGER.warn("该任务已经成功执行过");
	return false;
}else if(idempotentTask.getStatus() == 0){
	LOGGER.warn("该任务正在执行中");
	return false;
}else {
	//任务是失败状态
	IdempotentTask task = new IdempotentTask();
	task.setBusinessId(businessId);
	task.setCreated(new Date());
	task.setModified(new Date());

	//0表示初始化,1表示成功,-1表示失败
	task.setStatus(0);
	try {
		int result = idempotentTaskMapper.updateTask(task);
		if (result > 0){
			return true;
		}
	}catch (Exception e){
		e.printStackTrace();
	}
	return false;
}

4. 本次任务会在业务的末端做成功或失败的终态更新。

猜你喜欢

转载自blog.csdn.net/ghaohao/article/details/79670516