前言:
随着笔者的颜值不断提高,用户量的日益增长,传统的单机方案已经不能满足产品的需求。笔者在网上寻遍方案,发现均为人云亦云,一份以毫秒为精度的轮询分布式锁被转发转载上万次。然,该方案没法满足笔者性能要求。故此,笔者研发ELock插件,并发布本文章。
其实集群也好,分布式服务也好。当我们不能保证团队成员的整体素质,那么在某些业务上,分布式锁自然没法避免。
公认开发原则:能不使用分布式锁的,尽可能不使用
举个例子,一个商品交易,需要检查库存、检查余额、扣库存、扣款、生成订单。可能很多人觉得,在分布式环境下一定要分布式锁才能安全。
致此,笔者提供一种简单的方案:
订单处理{
if(库存不足){
return 库存不足;
}
if(余额不足){
return 余额不足;
}
事务管理(rollbackFor = Exception.class){
//扣库存
int changeLine = 执行语句(update 商品表 set 库存=库存-购买数量 where 库存>购买数量 and 商品ID = ?);
if(changeLine != 1){
return 库存不足;
}
double 扣款金额= 商品价格 x 购买数量;
//扣款
changeLine = 执行语句(update 用户余额表 set 余额=余额-扣款金额 where 余额 > 扣款金额 and 扣款金额 > 0 and 用户ID = ?);
if(changeLine != 1){
throw CustomRuntimeException("余额不足");
}
//生成订单
changeLine = 执行语句( insert into 订单表 set ......);
if(changeLine < 1){
throw CustomRuntimeException("订单生成失败");
}
}
}
我们仔细来分析一下如上的整个逻辑
1、当一个业务进入逻辑体,先检查余额和库存,不满足条件则返回错误(可阻挡非并发情况下的大部分业务流入事物)
2、进入事物后,先扣取库存,当扣取失败,直接返回错误
3、扣取库存后,则进行扣款,当扣款失败,则抛出异常(由于在业务体走到这里,已经扣取了库存,本处不能return,需抛出异常,让事物回滚)
4、扣款成功后,则生成订单,当订单生成失败,则抛出异常(理由同第三点)
特别注意:语句中,通过where来进行余额不足和库存不足的条件判断。通过执行语句返回的影响行数,来判断是否扣取成功。 在以上流程中,我们发现,即便不使用分布式锁,也无并发问题。
============================