事务中使用分布式锁问题

项目场景:

场景:监听订单中心支付完成消息,生成对应的用户订单,生成服务。加了分布式锁,但是还是有重复订单落库。


问题描述

集群模式下,采用分布式锁控制,保证只有一个服务能够得到执行。在获取到分布式锁之后,首先根据订单号查询有没有入库过,如果没有入库才能继续执行。因为要落多张表,所以在service层加了@Transactional控制事务。伪代码如下

	@Transactional(rollbackFor = Exception.class)
	public void createOrder(String orderId) {
		// 使用redission获取分布式锁,获取不到锁时进行等待
		lock.lock();
		try {
			// 获取到锁之后,先查询订单有没有入库,如果入库则忽略
			OrderDO existOrder = orderMapper.get(orderId);
			if (existOrder != null) {
				return;
			}
			// 以下落order表和orderService表
			OrderDO newOrder = new OrderDO();
			newOrder.setOrderId(orderId);
			orderMapper.insert(newOrder);
			OrderServiceDO orderService = new OrderServiceDO();
			orderServiceMapper.insert(orderService);
		} finally {
			lock.unLock();
		}
	}

原因分析:

分布式锁是在事务里面,假如有多个服务同时执行到了获取锁这一步,只会有一个服务能获取到锁,其他服务会等待锁的释放(redission是使用订阅的方式,由redis-server通知client锁的释放事件)。待方法业务逻辑执行完成之后,锁就进行了释放,但是事务还没有提交。其他服务这时获取到了锁,虽然在执行前有进行重复检查,但是因为前一个服务的事务还没有提交,这里是获取不到结果的(数据库隔离级别为可重复读),还是能正常执行下去。这就导致了重复数据入库。


解决方案:

1.分布式锁加事务的场景下,将分布式锁放在事务外面,当事务提交完成之后,才进行锁的释放。
2.数据库层面加唯一索引,防止重复的订单号入库。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值