我们在实现幂等接口的时候,例如处理微信支付回调,一般来说可以根据如下逻辑来实现幂等操作。
伪代码
// 根据订单号查询订单是否存在
步骤1、Order order = orderService.getOrder(orderNo);
// 判断状态是否成功
步骤2、if (order!=null && !order.getStatus().equalsIgnoreCase("success")){
步骤3、 // 更新订单成功,以及后续业务逻辑等等
}
假如同时过来两条请求,请求1和请求2的线程是可以同时走到步骤3的,此时系统会走两遍业务逻辑,对于金融业务来说这是不允许出现的。
那么有没有一种办法,既简单又可以避免这个问题呢。其实我们可以利用乐观锁的思想来实现幂等防并发问题。
控制层
Order order = orderService.getOrder(orderNo);
if (order!=null && order.getStatus().equalsIgnoreCase("init")){
order.setStatus("success");
orderService.updateOrder(order);
}
mybatis逻辑
update `order`
set status = #{status,jdbcType=VARCHAR},version=version+1
where id = #{id,jdbcType=INTEGER}
and version=#{version,jdbcType=INTEGER}
下面我们来测试下。
image.png
jmeter模拟100个并发
image.png
执行完数据库记录只更新了一次
image.png
乐观锁:
1.如果有人在你之前更新了,你的更新应当是被拒绝的,可以让用户重新操作。
2.实现:大多数基于数据版本(Version)记录机制实现
具体可通过给表加一个版本号或时间戳字段实现,当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断当前版本信息与第一次取出来的版本值大小,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据,拒绝更新,让用户重新操作。