分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)(上):https://developer.aliyun.com/article/1419992
转出微服务编写hmily配置文件
在项目的 resource 新建文件名为: hmily.yml 配置文件
hmily: server: configMode: local appName: user-account-bank01-dubbo # 如果server.configMode eq local 的时候才会读取到这里的配置信息. config: appName: user-account-bank01-dubbo serializer: kryo contextTransmittalMode: threadLocal scheduledThreadMax: 16 scheduledRecoveryDelay: 60 scheduledCleanDelay: 60 scheduledPhyDeletedDelay: 600 scheduledInitDelay: 30 recoverDelayTime: 60 cleanDelayTime: 180 limit: 200 retryMax: 10 bufferSize: 8192 consumerThreads: 16 asyncRepository: true autoSql: true phyDeleted: true storeDays: 3 repository: mysql repository: database: driverClassName: com.mysql.cj.jdbc.Driver url : jdbc:mysql://192.168.66.100:3306/hmily? useUnicode=true&characterEncoding=UTF8&useOldAliasMetadataBehavior=true&autoReconnec t=true&failOverReadOnly=false&useSSL=false&serv erTimezone=UTC username: root password: 123456 maxActive: 20 minIdle: 10 connectionTimeout: 30000 idleTimeout: 600000 maxLifetime: 1800000
实现接口上添加注解
TCC模式
Hmily实现TCC分布式事务_转入转出微服务实现Try阶段
转出微服务Try阶段
/** * 转账功能 * @param userAccountDTO */ @HmilyTCC(confirmMethod = "sayConfrim", cancelMethod = "sayCancel") @Override public void transferAmountToBank02(UserAccountDTO userAccountDTO) { String txNo = userAccountDTO.getTxNo(); log.info("********** 执行bank01 的 Try 方法 ,事务id={}",txNo); // 1、 幂等处理 TryLog tryLog = tryLogMapper.selectById(txNo); if (tryLog != null){ return ; } // 2、 悬挂处理 if (confirmLogMapper.selectById(txNo) != null || cancelLogMapper.selectById(txNo) != null){ return ; } // 3. 根据账户编号查询账户信息 UserAccount userAccount = baseMapper.selectById(userAccountDTO.getSourceAccountNo()); // 4. 判断账户是否存在 if (userAccount != null){ // 5. 账户金额更新 LambdaUpdateWrapper<UserAccount> ulw = new LambdaUpdateWrapper<>(); // 更新转账金额 ulw.set(UserAccount::getTransferAmount,userAccount.getTransferAmount().add(userAccountDTO.getBigDecimal())); // 更新余额 ulw.set(UserAccount::getAccountBalance,userAccount.getAccountBalance().subtract(userAccountDTO.getBigDecimal())); ulw.eq(UserAccount::getAccountNo,userAccountDTO.getSourceAccountNo()); baseMapper.update(null,ulw); } // 7. 准备阶段记录 TryLog tryLog1 = new TryLog(); tryLog1.setTxNo(txNo); tryLog1.setCreateTime(LocalDateTime.now()); tryLogMapper.insert(tryLog1); // 8. 远程调用 转入微服务 跨库转账的功能 userAccountBank02Service.transferAmountToBank02(userAccountDTO); }
转入微服务Try阶段
/** * 跨库转账 * @param userAccountDTO */ @HmilyTCC(confirmMethod = "sayConfrim", cancelMethod = "sayCancel") @Override public void transferAmountToBank02(UserAccountDTO userAccountDTO) { String txNo = userAccountDTO.getTxNo(); log.info("********** 执行bank02 的 Try方法 ,事务id={}",txNo); // 1、 幂等处理 TryLog tryLog = tryLogMapper.selectById(txNo); if (tryLog != null){ return ; } // 2、 悬挂处理 if (confirmLogMapper.selectById(txNo) != null || cancelLogMapper.selectById(txNo) != null){ return ; } // 3. 根据账户编号查询账户信息 UserAccount userAccount = userAccountMapper.selectById(userAccountDTO.getTargetAccountNo()); // 4. 判断账户是否存在 if (userAccount != null){ // 5. 账户金额更新 LambdaUpdateWrapper<UserAccount> ulw = new LambdaUpdateWrapper<>(); // 更新转账金额 ulw.set(UserAccount::getTransferAmount,userAccount.getTransferAmount().add(userAccountDTO.getBigDecimal())); ulw.eq(UserAccount::getAccountNo,userAccountDTO.getTargetAccountNo()); userAccountMapper.update(null,ulw); } // 7. 准备阶段记录 TryLog tryLog1 = new TryLog(); tryLog1.setTxNo(txNo); tryLog1.setCreateTime(LocalDateTime.now()); tryLogMapper.insert(tryLog1); }
Hmily实现TCC事务_转入转出微服务实现Confirm阶段
编写转出微服务Confirm阶段
/** * 确认阶段 * @param userAccountDTO */ public void sayConfrim(UserAccountDTO userAccountDTO) { String txNo = userAccountDTO.getTxNo(); log.info("********** 执行bank01 的 Confrim方法 ,事务id={}",txNo); // 1、幂等处理 ConfirmLog confirmLog = confirmLogMapper.selectById(txNo); if (confirmLog != null){ return ; } // 2、根据账户id查询账户 UserAccount userAccount = baseMapper.selectById(userAccountDTO.getSourceAccountNo()); userAccount.setTransferAmount(userAccount.getTransferAmount().subtract(userAccountDTO.getBigDecimal())); baseMapper.updateById(userAccount); // 3、 确认日志记录 ConfirmLog confirmLog1 = new ConfirmLog(); confirmLog1.setTxNo(userAccountDTO.getTxNo()); confirmLog1.setCreateTime(LocalDateTime.now()); confirmLogMapper.insert(confirmLog1); }
编写转入微服务Confirm阶段
/** * 确认阶段 * @param userAccountDTO */ public void sayConfrim(UserAccountDTO userAccountDTO) { String txNo = userAccountDTO.getTxNo(); log.info("********** 执行bank02 的Confrim方法 ,事务id={}",txNo); // 1、幂等处理 ConfirmLog confirmLog = confirmLogMapper.selectById(txNo); if (confirmLog != null) { return; } // 2、根据账户id查询账户 UserAccount userAccount = userAccountMapper.selectById(userAccountDTO.getTargetAccountNo()); userAccount.setAccountBalance(userAccount.getAccountBalance().add(userAccountDTO.getBigDecimal())); userAccount.setTransferAmount(userAccount.getTransferAmount().subtract(userAccountDTO.getBigDecimal())); userAccountMapper.updateById(userAccount); // 3、 确认日志记录 ConfirmLog confirmLog1 = new ConfirmLog(); confirmLog1.setTxNo(userAccountDTO.getTxNo()); confirmLog1.setCreateTime(LocalDateTime.now()); confirmLogMapper.insert(confirmLog1); }
Hmily实现TCC分布式事务_转入转出微服务实现Cancel阶段
转入微服务Cananl阶段
/** * 回滚 * @param userAccountDto */ @Transactional(rollbackFor = Exception.class) public void cancelMethod(UserAccountDto userAccountDto){ String txNo = userAccountDto.getTxNo(); log.info("执行bank02的cancel方法,事务id: {}, 参数为:{}",txNo,JSONObject.toJSONString(userAccountDto)); CancelLog cancelLog = iCancelLogService.findByTxNo(txNo); if(cancelLog != null){ log.info("bank02已经执行过Cancel方法,txNo:{}", txNo); return; } // 保存记录 iCancelLogService.saveCancelLog(txNo); userAccountMapper.cancelUserAccountBalanceBank02(userAccountDto.getAmount(), userAccountDto.getTargetAccountNo()); }
转出微服务Cancel阶段
/** * 取消阶段 * @param userAccountDTO */ public void sayCancel(UserAccountDTO userAccountDTO) { String txNo = userAccountDTO.getTxNo(); log.info("********** 执行bank01 的 Cancel方法 ,事务id={}",txNo); // 1. 幂等处理 CancelLog cancelLog = cancelLogMapper.selectById(txNo); if (cancelLog != null ){ return; } // 2、根据账户id查询账户 UserAccount userAccount = baseMapper.selectById(userAccountDTO.getSourceAccountNo()); userAccount.setAccountBalance(userAccount.getAccountBalance().add(userAccountDTO.getBigDecimal())); userAccount.setTransferAmount(userAccount.getTransferAmount().subtract(userAccountDTO.getBigDecimal())); baseMapper.updateById(userAccount); // 3、记录回滚日志 CancelLog cancelLog1 = new CancelLog(); cancelLog1.setTxNo(txNo); cancelLog1.setCreateTime(LocalDateTime.now()); cancelLogMapper.insert(cancelLog1); }
最终一致性分布式事务解决方案_什么是可靠消息最终一致性事务
可靠消息最终一致性的基本原理是事务发起方(消息发送者)执行 本地事务成功后发出一条消息,事务参与方(消息消费者)接收到 事务发起方发送过来的消息,并成功执行本地事务。事务发起方和事务参与方最终的数据能够达到一致的状态。
两种实现方式:
1、基于本地消息表
2、基于支持分布式事务的消息中间件,如RocketMQ等
基本原理
在使用可靠消息最终一致性方案解决分布式事务的问题时,需要确保消息发送和消息消费的一致性,从而确保消息的可靠性。
可靠消息最终一致性分布式事务实现_本地消息表
本地消息表模式的核心通过本地事务保证数据业务操作和消息的一 致性,然后通过定时任务发送给消费方或者中间加一层MQ的方 式,保障数据最终一致性。
库表设计
订单微服务中出库本地消息表:
基础功能
分析
Task微服务的任务