✅库存扣减、创建订单,如何拆成TCC?

✅库存扣减、创建订单,如何拆成TCC?

典型回答

这是一个比较典型的场景题,考察对TCC的理解。

我们先来回顾一下TCC。

✅什么是TCC,和2PC有什么区别?

所谓TCC,就是把一个操作拆分成Try\Confirm\Cancel三个步骤,并且这三个动作已经不是一个事务了,而是三个不同的事务。

怎么理解上面这句话呢?

Try\Confirm\Cancel分别是三个不同的方法,站在事务参与者的角度,在代码中,每一次调用Try或者Confirm或者Cancel的时候,都会单独开启一个数据库事务(如果数据库支持的话),这就是2PC比较大的区别,2PC从头到尾就一个事务。

那么TCC如何拆呢?其实再看下TCC的定义:

  • Try阶段:执行业务检查,预留资源
  • Confirm阶段:若所有Try成功,提交资源
  • Cancel阶段:若任一Try失败,释放预留资源

那么回到问题上,针对库存扣减,如何拆解成TCC呢?

  • Try阶段:执行业务检查,预留资源
    • 冻结库存
    • <font style="color:rgb(64, 64, 64);">update inventory_table set frozen_inventory = frozen_inventory + #{count} where id = xxx</font>
    • <font style="color:rgb(64, 64, 64);">冻结库存</font> + 1,用户看到的<font style="color:rgb(64, 64, 64);">可用库存</font> = <font style="color:rgb(64, 64, 64);">剩余库存</font> - <font style="color:rgb(64, 64, 64);">冻结库存</font> ,那么,这就起到了资源预留的作用。
  • Confirm阶段:若所有Try成功,提交资源
    • 解冻并扣减库存
    • <font style="color:rgb(64, 64, 64);">update inventory_table set frozen_inventory = frozen_inventory - #{count},saleable_inventory = saleable_inventory - #{count} where id = xxx</font>
    • <font style="color:rgb(64, 64, 64);">冻结库存</font> - 1, <font style="color:rgb(64, 64, 64);">剩余库存</font> - 1,即真正做库存扣减。
  • Cancel阶段:若任一Try/Confirm失败,释放预留资源
    • 解冻库存
    • <font style="color:rgb(64, 64, 64);">update inventory_table set frozen_inventory = frozen_inventory - #{count} where id = xxx</font>
    • <font style="color:rgb(64, 64, 64);">冻结库存</font> - 1, 即释预留资源
  • Cancel阶段:若Confirm成功,但是其他参与者失败,需要回滚Confirm操作
    • 回退库存
    • <font style="color:rgb(64, 64, 64);">update inventory_table set saleable_inventory = saleable_inventory + #{count} where id = xxx</font>
    • <font style="color:rgb(64, 64, 64);">剩余库存</font> + 1,即回退库存扣减操作。

针对订单创建,如何拆解成TCC呢?

  • Try阶段:执行业务检查,预留资源
    • 创建订单,但是订单用户不可见,无法支付
    • <font style="color:rgb(64, 64, 64);">insert into order(id,time,order_id,state) value(1,now(),12345,"INIT") </font>
    • 创建一个INIT状态的订单,这个状态用户不感知
  • Confirm阶段:若所有Try成功,提交资源
    • <font style="color:rgb(64, 64, 64);">update order set state = 'TO_PAY' where id = xxx</font>
    • 订单状态推荐到待支付状态,这时候用户就能看到这个订单了。可以去做支付了
  • Cancel阶段:若任一Try/Confirm失败,释放预留资源
    • <font style="color:rgb(64, 64, 64);">update order set state = 'DISCARD' where id = xxx</font>
    • 订单废弃掉,废弃的订单无法查看,也无法操作,可以定期清理掉。
  • Cancel阶段:若Confirm成功,但是其他参与者失败,需要回滚Confirm操作
    • <font style="color:rgb(64, 64, 64);">update order set state = 'DISCARD' where id = xxx</font>
    • 订单废弃掉,废弃的订单无法查看,也无法操作,可以定期清理掉。

所以,你在回过头来看前面说TCC是三个事务的说法,是不是就理解,三个不同的SQL,每一个都是单独事务执行的。

PS:这个TCC在我的项目课中有落地实践,代码+视频+文档。有需要的可以了解下。