事务回滚函数的设计
大二某个深夜使用反射写了一个事务回滚函数解决生成预订单过程中可能失败需要回退库存、优惠券的问题。
20年写的,躺在草稿中至今才想起。。。
事务回滚类设计:
1.RollBack类
@Slf4j
public class RollBack {
private static final String METHOD_SUFFIX="RollBack";
private Stack<ObjMethod> methodStack =new Stack<>();
private Stack<Object> objStack=new Stack<>();
public void pushMethod(Object obj,String method,Object... params) throws Exception {
Class[] classes=new Class[params.length];//参数类型列表
int i=0;
for (Object param : params) {
classes[i++]=param.getClass();
}
Method m= obj.getClass().getDeclaredMethod(method+METHOD_SUFFIX,classes);//获取该方法对应的RollBack方法
ObjMethod objMethod=new ObjMethod(m,params);
objStack.push(obj);
methodStack.push(objMethod);
}
public void popMethod(){
methodStack.pop();
objStack.pop();
}
public void rollBack() throws Exception{
if(!methodStack.isEmpty()) popMethod();//最后一次事务未成功执行,无需回滚
while(!methodStack.isEmpty()){
ObjMethod objMethod= methodStack.pop();
Object obj=objStack.pop();
objMethod.getMethod().invoke(obj,objMethod.getParams());
log.info("Call "+objMethod.getMethod().getName());
}
}
}
2.ObjMethod
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ObjMethod {
private Method method;
private Object[] params;
}
Demo
1.确认订单业务
public Result confirmOrder(Order order) {
RollBack RollBack=new RollBack();//必选建立局部变量
//1. 校验订单
Result result = checkOrder.checkOrder(order);
if(result != null) return result;
log.info("订单校验通过.");
//2. 生成预订单
result = savePreOrder.savePreOrder(order);
if(result != null)
log.info("成功生成预订单.。。");
try {
boolean res;
//3.扣减库存
res=goodsService.reduceGoodsNum(order.getGoodsId(),order.getGoodsNumber());
RollBack.pushMethod(goodsService,"reduceGoodsNum",order.getGoodsId(),order.getGoodsNumber());
if(!res) throw new ShopException(ShopCode.SHOP_GOODS_NO_Exist,"库存不足");
log.info("成功扣减库存.");
//4.扣减优惠券
res=couponService.setUsedStatus(order.getUserId());
RollBack.pushMethod(couponService,"setUsedStatus",order.getUserId());
if(!res) throw new ShopException(ShopCode.SHOP_COUPON_NO_Exist,"优惠券不够");
log.info("扣减优惠券成功");
//5.使用余额
res= userService.reduceMoney(order.getUserId(),order.getOrderAmount());
RollBack.pushMethod(userService,"reduceMoney",order.getUserId(),order.getOrderAmount());
if(!res) throw new ShopException(ShopCode.SHOP_USER_INSUFFICIENT_BALANCE,"余额不足");
log.info("扣余额");
//6.确认订单
order.setOrderStatus(STATUS_COMFIRM);
orderDao.update(order,null);
} catch (ShopException e) {
//1.确认订单失败,发送回滚指令
try {
RollBack.rollBack();
} catch (Exception ex) {ex.printStackTrace();}
//2.返回失败状态
return new Result(e.getCode(),e.getMessage());
}catch(Exception e){ return new Result(ShopCode.SHOP_ERROR,"Server Error");}
//7.返回成功状态
return new Result(ShopCode.SHOP_ORDER_NORMAL, "success.", order);
}
2.IGoodsService
@Slf4j
@Component
@DubboService(interfaceClass = IGoodsService.class)
public class GoodsServiceImpl implements IGoodsService {
@Resource
private GoodsDao goodsDao;
@Override
public Goods selectGoodsById(Integer goodsId) {
return goodsDao.selectById(goodsId);
}
@Override
public boolean reduceGoodsNum(Integer goodsId,Integer num) {
if(selectGoodsById(goodsId).getGoodsNumber()<num) return false;
goodsDao.reduceGoodsNum(goodsId,num);
return true;
}
@Override
public void reduceGoodsNumRollBack(Integer goodsId,Integer num){
goodsDao.reduceGoodsNum(goodsId,-num);
}
}