分布式事务问题
以电商业务为例,订单服务对应的订单数据库,库存服务对应的库存数据库,多个数据源之间存在了分布式事务问题。如何保证在订单生成后,正确的扣除库存,或者在订单生成失败时,还原扣除的库存,这就是分布式事务将要解决的问题。
解决分布式事务前的业务逻辑:
@Transaction(rollbackFor=Exception.class)
public void createOrder(OrderInfo orderInfo) throws Exception {
// 订单系统 —— 生成订单
orderService.saveOrder(orderInfo);
// 库存系统 —— 扣除库存
if(!"success".equals(reduceStock(orderInfo))){
throw new Exception("订单创建失败,原因:库存扣除失败!");
}
}
上述存在的问题:
-
库存服务的接口调用成功,订单数据库事务提交失败,库存没有回滚,导致订单生成失败但扣除了库存
-
库存服务的接口调用超时,订单系统数据库事务被回滚,库存系统接口继续执行,导致订单生成失败但扣除了库存
Part3解决方案
生产者:订单系统将订单信息的消息发送到 RabbitMQ 中,消息到达交换机后通过 confirm 机制将接收成功的消息返回给订单系统(生产者),生产者收到正确的 confirm 后给用户返回订单创建成功的响应。
队列:为了防止 RabbitMQ 在收到消息后还未发送给消费者处理就挂了的情况,将队列和消息分别持久化。
消费者:消费者接收到消息后,为了确保消息能够被成功正确的处理,需要考虑消息丢失问题和消息幂等性等问题。
可靠的发送消息
在订单系统创建订单的事务中添加把消息保存到订单数据库的业务逻辑,将消息在生产者中持久化。
public class OrderDBService {
public void createOrder(OrderInfo orderInfo) throws Exception {
// 创建订单
String sql = "...";
int count = jdbcTemplate.insert(sql);
if(count