详细说分布式事务
一、分布式事务的概念
回到顶部回到顶部回到顶部https://github.com/changmingxie/tcc-transactiona)导入数据库
sql文件下载地址为:dtx-tcc-sql
b)工程配置
涉及到分布式事务的工程均需要的配置
maven配置
org.dromara hmily‐springcloud 2.0.4‐RELEASE
application.yaml中添加hmily
org: dromara: hmily: serializer: kryo recoverDelayTime: 30 retryMax: 30 scheduledDelay: 30 scheduledThreadMax: 10 repositorySupport: db #对于发起方的时候,把此属性设置为true。参与方为false。 started: true hmilyDbConfig: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/hmily?useUnicode=true username: root password: 123456
注入hmily的配置Bean
@Bean public HmilyTransactionBootstrap hmilyTransactionBootstrap(HmilyInitService hmilyInitService){ HmilyTransactionBootstrap hmilyTransactionBootstrap = new HmilyTransactionBootstrap(hmilyInitService); hmilyTransactionBootstrap.setSerializer(env.getProperty("org.dromara.hmily.serializer")); hmilyTransactionBootstrap.setRecoverDelayTime(Integer.parseInt(env.getProperty("org.dromara.hmily.recoverDelayTime"))); hmilyTransactionBootstrap.setRetryMax(Integer.parseInt(env.getProperty("org.dromara.hmily.retryMax"))); hmilyTransactionBootstrap.setScheduledDelay(Integer.parseInt(env.getProperty("org.dromara.hmily.scheduledDelay"))); hmilyTransactionBootstrap.setScheduledThreadMax(Integer.parseInt(env.getProperty("org.dromara.hmily.scheduledThreadMax"))); hmilyTransactionBootstrap.setRepositorySupport(env.getProperty("org.dromara.hmily.repositorySupport")); hmilyTransactionBootstrap.setStarted(Boolean.parseBoolean(env.getProperty("org.dromara.hmily.started"))); HmilyDbConfig hmilyDbConfig = new HmilyDbConfig(); hmilyDbConfig.setDriverClassName(env.getProperty("org.dromara.hmily.hmilyDbConfig.driverClassName")); hmilyDbConfig.setUrl(env.getProperty("org.dromara.hmily.hmilyDbConfig.url")); hmilyDbConfig.setUsername(env.getProperty("org.dromara.hmily.hmilyDbConfig.username")); hmilyDbConfig.setPassword(env.getProperty("org.dromara.hmily.hmilyDbConfig.password")); hmilyTransactionBootstrap.setHmilyDbConfig(hmilyDbConfig); return hmilyTransactionBootstrap; }
启动类上添加注解
@ComponentScan({"org.dromara.hmily"})
c)调用方(bank1)实现
代码实现:AccountInfoServiceImpl
try: try幂等校验 try悬挂处理 检查余额是够扣减金额 扣减金额 confirm: 空 cancel cancel幂等校验 cancel空回滚处理 增加可用余额
注意:远程调用bank2时,在feign调用的接口上加注解@Hmily
d)参与方(bank2)实现
代码实现:AccountInfoServiceImpl
try: 空 confirm: confirm幂等校验 正式增加金额 cancel: 空
e)小结
如果拿TCC事务的处理流程与2PC两阶段提交做比较,2PC通常都是在跨库的DB层面,而TCC则在应用层面的处理,需要通过业务逻辑来实现。这种分布式事务的实现方式的优势在于,可以让应用自己定义数据操作的粒度,使得降低锁冲突、提高吞吐量成为可能。 而不足之处则在于对应用的侵入性非常强,业务逻辑的每个分支都需要实现try、confirm、cancel三个操作。此外,其实现难度也比较大,需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。 回到顶部cloud-dtx-txmsg AccountInfoServiceImpl//两个方法 //1,向mq发送转账消息 //2,更新账户,扣减金额 (通过事务id保证幂等性)
Controller:AccountInfoController
//生成事务id,调用service的发消息接口
message:ProducerTxmsgListener
//两个方法executeLocalTransaction和checkLocalTransaction //事务消息发送后的回调方法。此时保证本地事务,调用Service扣减金额同时将消息改为COMMIT(可消费状态),如果捕获异常,将消息改为ROLLBACK回滚 //事务回查。查询是否在调用方已经处理,如果已经处理需修改消息为COMMIT可消费,否则就是UNKOWN状态。
e)bank2
Service:AccountInfoServiceImpl
//更新账户bank2,增加金额。(通过事务id保证幂等性)
message:TxmsgConsumer
//监听bank1发送的消息topic,调用Service增加金额回到顶部cloud-dtx-notify AccountPayServiceImpl
//两个方法 //1,插入充值记录。生成事务id,将事务id和充值信息发送给MQ队列 //2,查询充值记录。提供给调用方查询。
Controller:AccountPayController
//直接调用Service中的方法插入充值记录
d)bank1
Service:AccountInfoServiceImpl
//两个方法 //1,更新账户金额。根据事务id保证更新的幂等性。 //2,远程调用pay的查询充值结果。如果发现状态改变同时更新当前账号情况。
message:NotifyMsgListener
//监听消息。调用Service的更新账户金额,幂等更新。
Controller:AccountInfoController
//调用Service的查询充值结果
5,总结
最大努力通知方案是分布式事务中对一致性要求最低的一种,适用于一些最终一致性时间敏感度低的业务;最大努力通知方案需要实现如下功能:
- 消息重复通知机制。
- 消息校对机制。 主动调用接口查询并修改。