(2)Seata AT和RocketMQ 事务消息事务方式代码实例

好的,我将为你详细讲解分布式事务在 Java Web 项目中的实践,并提供一个完整的基于 Seata AT 模式RocketMQ 事务消息 的代码示例。

方案一:使用 Seata AT 模式(无侵入方案)

环境准备

  1. 下载 Seata Server
wget https://github.com/seata/seata/releases/download/v1.5.2/seata-server-1.5.2.zip
unzip seata-server-1.5.2.zip
  1. 修改配置文件 (conf/application.yml):
seata:
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: ""
      group: SEATA_GROUP
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      namespace: ""
      group: SEATA_GROUP

数据库准备

每个服务的数据库中都需要创建 undo_log 表:

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

代码实现

1. 订单服务 (Order Service)

pom.xml 依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <version>2021.0.1.0</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/order_db
    username: root
    password: root
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

seata:
  tx-service-group: my_test_tx_group
  service:
    vgroup-mapping:
      my_test_tx_group: default

OrderController.java

@RestController
@RequestMapping("/order")
public class OrderController {
    
    @Autowired
    private OrderService orderService;
    
    @PostMapping("/create")
    public String createOrder(@RequestBody OrderDTO orderDTO) {
        orderService.createOrder(orderDTO);
        return "订单创建成功";
    }
}

OrderService.java

@Service
public class OrderServiceImpl implements OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private AccountFeignClient accountFeignClient;
    
    @Autowired
    private StorageFeignClient storageFeignClient;
    
    @Override
    @GlobalTransactional(name = "create-order-tx", rollbackFor = Exception.class)
    public void createOrder(OrderDTO orderDTO) {
        // 1. 创建订单
        Order order = new Order();
        order.setUserId(orderDTO.getUserId());
        order.setProductId(orderDTO.getProductId());
        order.setCount(orderDTO.getCount());
        order.setMoney(orderDTO.getMoney());
        order.setStatus(0); // 0-创建中
        orderMapper.insert(order);
        
        // 2. 扣减库存
        storageFeignClient.decrease(orderDTO.getProductId(), orderDTO.getCount());
        
        // 3. 扣减余额
        accountFeignClient.decrease(orderDTO.getUserId(), orderDTO.getMoney());
        
        // 4. 修改订单状态
        order.setStatus(1); // 1-已完成
        orderMapper.updateById(order);
    }
}
2. 库存服务 (Storage Service)

StorageController.java

@RestController
@RequestMapping("/storage")
public class StorageController {
    
    @Autowired
    private StorageService storageService;
    
    @PostMapping("/decrease")
    public String decrease(@RequestParam Long productId, @RequestParam Integer count) {
        storageService.decrease(productId, count);
        return "库存扣减成功";
    }
}

StorageService.java

@Service
public class StorageServiceImpl implements StorageService {
    
    @Autowired
    private StorageMapper storageMapper;
    
    @Override
    @Transactional
    public void decrease(Long productId, Integer count) {
        Storage storage = storageMapper.selectByProductId(productId);
        if (storage.getResidue() < count) {
            throw new RuntimeException("库存不足");
        }
        storage.setResidue(storage.getResidue() - count);
        storage.setUsed(storage.getUsed() + count);
        storageMapper.updateById(storage);
    }
}
3. 账户服务 (Account Service)

AccountController.java

@RestController
@RequestMapping("/account")
public class AccountController {
    
    @Autowired
    private AccountService accountService;
    
    @PostMapping("/decrease")
    public String decrease(@RequestParam Long userId, @RequestParam BigDecimal money) {
        accountService.decrease(userId, money);
        return "账户扣减成功";
    }
}

AccountService.java

@Service
public class AccountServiceImpl implements AccountService {
    
    @Autowired
    private AccountMapper accountMapper;
    
    @Override
    @Transactional
    public void decrease(Long userId, BigDecimal money) {
        Account account = accountMapper.selectByUserId(userId);
        if (account.getBalance().compareTo(money) < 0) {
            throw new RuntimeException("余额不足");
        }
        account.setBalance(account.getBalance().subtract(money));
        accountMapper.updateById(account);
    }
}

方案二:使用 RocketMQ 事务消息(最终一致性方案)

环境准备

  1. 启动 RocketMQ
nohup sh bin/mqnamesrv &
nohup sh bin/mqbroker -n localhost:9876 &

代码实现

订单服务 (Order Service)

OrderServiceWithMQ.java

@Service
@Slf4j
public class OrderServiceWithMQ {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    
    /**
     * 创建订单并发送事务消息
     */
    @Transactional
    public void createOrderWithTransactionMessage(OrderDTO orderDTO) {
        // 1. 创建订单(状态为待确认)
        Order order = new Order();
        order.setUserId(orderDTO.getUserId());
        order.setProductId(orderDTO.getProductId());
        order.setCount(orderDTO.getCount());
        order.setMoney(orderDTO.getMoney());
        order.setStatus(0); // 0-创建中
        orderMapper.insert(order);
        
        // 2. 发送半事务消息
        TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(
            "order-transaction-topic",
            MessageBuilder.withPayload(orderDTO).setHeader("order_id", order.getId()).build(),
            order
        );
        
        log.info("发送事务消息结果: {}", sendResult.getSendStatus());
    }
    
    /**
     * 事务消息本地事务执行器
     */
    @RocketMQTransactionListener
    public class OrderTransactionListenerImpl implements RocketMQLocalTransactionListener {
        
        @Override
        public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
            try {
                Order order = (Order) arg;
                // 这里可以执行一些本地检查
                // 如果本地事务执行成功,返回COMMIT
                return RocketMQLocalTransactionState.COMMIT;
            } catch (Exception e) {
                log.error("本地事务执行失败", e);
                return RocketMQLocalTransactionState.ROLLBACK;
            }
        }
        
        @Override
        public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
            // 检查本地事务状态
            String orderId = msg.getHeaders().get("order_id", String.class);
            Order order = orderMapper.selectById(orderId);
            
            if (order != null && order.getStatus() == 1) {
                return RocketMQLocalTransactionState.COMMIT;
            } else {
                return RocketMQLocalTransactionState.ROLLBACK;
            }
        }
    }
}
库存服务 (Storage Service)

StorageMQListener.java

@Service
@RocketMQMessageListener(
    topic = "order-transaction-topic",
    consumerGroup = "storage-consumer-group"
)
@Slf4j
public class StorageMQListener implements RocketMQListener<OrderDTO> {
    
    @Autowired
    private StorageService storageService;
    
    @Override
    public void onMessage(OrderDTO orderDTO) {
        try {
            // 扣减库存(需要保证幂等性)
            storageService.decrease(orderDTO.getProductId(), orderDTO.getCount());
            log.info("库存扣减成功: {}", orderDTO);
        } catch (Exception e) {
            log.error("库存扣减失败: {}", orderDTO, e);
            // 可以加入重试机制或者死信队列
            throw new RuntimeException(e);
        }
    }
}
账户服务 (Account Service)

AccountMQListener.java

@Service
@RocketMQMessageListener(
    topic = "order-transaction-topic",
    consumerGroup = "account-consumer-group"
)
@Slf4j
public class AccountMQListener implements RocketMQListener<OrderDTO> {
    
    @Autowired
    private AccountService accountService;
    
    @Override
    public void onMessage(OrderDTO orderDTO) {
        try {
            // 扣减余额(需要保证幂等性)
            accountService.decrease(orderDTO.getUserId(), orderDTO.getMoney());
            log.info("账户扣减成功: {}", orderDTO);
        } catch (Exception e) {
            log.error("账户扣减失败: {}", orderDTO, e);
            throw new RuntimeException(e);
        }
    }
}

方案对比和选择建议

特性

Seata AT 模式

RocketMQ 事务消息

一致性

强一致性

最终一致性

性能

中等

侵入性

中等

复杂度

中等

适用场景

需要强一致性的业务

高并发、允许短暂不一致的业务

最佳实践建议

  1. 根据业务场景选择方案
    • 金融核心系统:选择 Seata AT 或 TCC 模式
    • 电商业务:选择 RocketMQ 事务消息
    • 混合使用:核心链路用 Seata,非核心用 MQ
  1. 保证幂等性
@Service
public class StorageService {
    
    @Autowired
    private StorageMapper storageMapper;
    
    @Transactional
    public void decrease(Long productId, Integer count, String transactionId) {
        // 检查是否已经处理过
        if (isProcessed(transactionId)) {
            return;
        }
        
        // 执行业务逻辑
        Storage storage = storageMapper.selectByProductId(productId);
        storage.setResidue(storage.getResidue() - count);
        storageMapper.updateById(storage);
        
        // 记录处理状态
        recordProcessed(transactionId);
    }
}
  1. 设置重试机制和监控
rocketmq:
  consumer:
    delay-level-when-next-consume: 0
    max-reconsume-times: 3
  1. 人工补偿机制
    • 对于始终失败的消息,进入死信队列
    • 提供管理界面进行人工干预和处理

这种分布式事务实践方案已经在大量生产环境中得到验证,能够有效解决微服务架构下的数据一致性问题。

标题基于SpringBoot的马术俱乐部管理系统设计与实现AI更换标题第1章引言介绍马术俱乐部管理系统的研究背景、意义、国内外研究现状、论文方法及创新点。1.1研究背景与意义阐述马术俱乐部管理系统对提升俱乐部管理效率的重要性。1.2国内外研究现状分析国内外马术俱乐部管理系统的发展现状及存在的问题。1.3研究方法以及创新点概述本文采用的研究方法,包括SpringBoot框架的应用,以及系统的创新点。第2章相关理论总结评述与马术俱乐部管理系统相关的现有理论。2.1SpringBoot框架理论介绍SpringBoot框架的基本原理、特点及其在Web开发中的应用。2.2数据库设计理论阐述数据库设计的基本原则、方法以及在管理系统中的应用。2.3马术俱乐部管理理论概述马术俱乐部管理的基本理论,包括会员管理、课程安排等。第3章系统设计详细描述马术俱乐部管理系统的设计方案,包括架构设计、功能模块设计等。3.1系统架构设计给出系统的整体架构,包括前端、后端数据库的交互方式。3.2功能模块设计详细介绍系统的各个功能模块,如会员管理、课程管理、预约管理等。3.3数据库设计阐述数据库的设计方案,包括表结构、字段设计以及数据关系。第4章系统实现介绍马术俱乐部管理系统的实现过程,包括开发环境、编码实现等。4.1开发环境搭建介绍系统开发所需的环境,包括操作系统、开发工具等。4.2编码实现详细介绍系统各个功能模块的编码实现过程。4.3系统测试与调试阐述系统的测试方法、测试用例以及调试过程。第5章系统应用与分析呈现马术俱乐部管理系统的应用效果,并进行性能分析。5.1系统应用情况介绍系统在马术俱乐部中的实际应用情况。5.2系统性能分析从响应时间、并发处理能力等方面对系统性能进行分析。5.3用户反馈与改进收集用户反馈,提出系统改进建议。第6章结论与展望总结马术俱乐部管理系统的设计与实现成果,并展望未来的研究
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值