本博只是自己刚学习seata的思路,若有问题可以指出
举个栗子,如RabbitMQ
1.先说MQ。我们用户一个下订单一个事务,在OrderProvider的service里通过Feign远程调用:
@Autowired
private RabbitTemplate templete;
public void startkill(Long id, String money,String count) {
//写入rabbitmq的消息内容需要先封装一下
String msg = id + "/" + money+ "/" + count;
//利用id可以在消费端获取商品信息,一旦秒杀成功,减少库存
//userPhone作为用户信息,成功则入库,失败则返回
//将消息写入队列
templete.convertAndSend("rabbitmq-seckill", "seckill", msg);
}
2.在发送端发送消息后,AccountProvider和StorageProvider就可以消费端接收这个“msg”,进行减库存,减余额操作。当然,要记录像seata使用的前镜像和后镜像记录Account和Storage的数据库undo段。并且要通过一个全局ID来记录这些操作,并保存到表里。
(到这里我已经完全跟着seata的思路走了😅)
---------------------------
这里说下为什么用MQ:
1.解耦。
现在有 Service A / Service B,三者构成某分布式事务。
如果用 rpc,A / B 彼此是不是得知道对方(哪怕用注册中心不也有个调用过程)?用消息队列的话,彼此压根不需要知道对方,只需要跟消息队列打交道就可以了。
你硬要用 rpc 也行,那这时候又多俩 Service C / Service D 出来呢?你回过头还得去改 A / B 的代码吗?都你自己写的你说你费点儿劲,那也行;如果是两个不同 Team 在干活呢?人家凭啥加班帮你改,自己的任务不做了吗?
2.mq的作用就是解耦、异步、削峰,实现分布式事务的最终一致性,是柔性事务。
不考虑并发,直接rpc或http就需要考虑分布式事务如何保证,当然也有对应的分布式事务框架可以补。
两种实现没有优劣之分,针对不同场景使用不同的方式,只不过mq在高并发中比较常见。
-----------------------------
3.当AccountProvider的减余额操作超时或失败了。通过OrderProvider的try{...}catch{从回滚表记录的开始回滚}
具体步骤没有我没有去实现,可能写着写着会发现不太对=。=(太懒了,等有时间再补)
seata专门用分布式事务的,官方文档说的更清楚: