前言
面试官就是想找事情,讲的好好的分布式事务方案,给你来断电,断电首先肯定去充电费啊。
场景
举一个电商常见的下单场景,伪代码如下
String createOrder(CreateOrderRequest request){
try{
transactionManger.execute((status)->{
//锁定优惠券
//校验,构造订单
//同步订单中心
//使用优惠券
//同步支付中心
})
}catch(Exception ex){
//回滚订单中心(重试)
//解锁优惠券(先同步解锁优惠券,失败重试)
}
}
上述代码,一旦try里面抛出异常,异常会自动回滚本地事务,因为使用的是编程式事务,我们捕获到异常,对第三方事务进行回滚。
这个方案看起来挺完美,能够保证最终一致性。
但是爱找事的面试官,问到,运行过程中断电了怎么办?
比如说,调用同步支付中心的时候断电了,但是订单中心和优惠中心的接口已经调用成功,现在存在的情况就是用户刷新订单列表能看到订单,但是支付不了。
解决方案
断电?我是不知道怎么解决的。
但是我们可以看看我们一些常见的中间件是如何解决这个问题的。
比如Mysql。
如果Mysql断电了,进行到一半的事务怎么回滚,还没刷盘的数据如何恢复。
它有undolog和redolog。
那么我们只需要在应用层创建自己的事务以及undolog就行了。
修改下上面的伪代码
String createOrder(CreateOrderRequest request){
//开启应用级别事务
try{
transactionManger.execute((status)->{
//开启应用级别事务
//记录锁定优惠券 记录undolog
//锁定优惠券
//校验,构造订单
//记录同步订单中心 记录undolog
//同步订单中心
//使用优惠券 记录undolog
//同步支付中心 记录undolog
//结束应用级别事务
})
//确认应用级别事务
}catch(Exception ex){
//回滚应用级别事务
}
}
如果断电了,我们只需要后台一个线程去扫描那些超过一定期限没提交的事务,执行对应undolog的回滚逻辑。
总结
上面的方案纯属我自己的YY,在面试过程中,遇到这些变态的即兴问题,我觉得我这个方案回答的也还算可以。
即兴发挥才能考验你对自己学习的知识是否真的吸收,能否举一反三。