JTA(Java Transaction Manager):
- Transaction Manager:常用方法,可以开启,回滚,获取事务 。begin(),rollback()...
- XAResouce:资源管理,通过 Session 来进行事务管理,commit(xid)...
- XID : 每一个事务都分配一个特定的 XID 。
如果前面出现了错误或是没有提交,那么第二阶段就不会提交,而是直接回滚,这样所有的事务都会做回滚操作 。基于 JTA 这种方案实现分布式事务的强一致性 。
JTA 的特点:
- 基于两阶段提交,有可能会出现数据不一致的情况
- 事务时间过长,阻塞
- 性能低,吞吐量低
正常架构设计中是否应该出现这种跨库的操作,我觉得是不应该的,如果按业务拆分将数据源进行分库,我们应该同时将服务也拆分出去才合适,应遵循一个系统只操作一个数据源(主从没关系),避免后续可能会出现的多个系统调用一个数据源的情况 。
最终一致性分布式事务方案
JTA 方案适用于单体架构多数据源时实现分布式事务,但对于微服务间的分布式事务就无能为力了,我们需要使用其他的方案实现分布式事务 。
①本地消息表
本地消息表的核心思想是将分布式事务拆分成本地事务进行处理 。
以本文中例子,在订单系统新增一条消息表,将新增订单和新增消息放到一个事务里完成,然后通过轮询的方式去查询消息表,将消息推送到 MQ,库存系统去消费 MQ 。

文章插图
执行流程:
- 订单系统,添加一条订单和一条消息,在一个事务里提交 。
- 订单系统,使用定时任务轮询查询状态为未同步的消息表,发送到 MQ,如果发送失败,就重试发送 。
- 库存系统,接收 MQ 消息,修改库存表,需要保证幂等操作 。
- 如果修改成功,调用 RPC 接口修改订单系统消息表的状态为已完成或者直接删除这条消息 。
- 如果修改失败,可以不做处理,等待重试 。
本地消息表这种方案实现了最终一致性,需要在业务系统里增加消息表,业务逻辑中多一次插入的 DB 操作,所以性能会有损耗,而且最终一致性的间隔主要由定时任务的间隔时间决定 。
②MQ 消息事务
消息事务的原理是将两个事务通过消息中间件进行异步解耦 。
订单系统执行自己的本地事务,并发送 MQ 消息,库存系统接收消息,执行自己的本地事务 。
乍一看,好像跟本地消息表的实现方案类似,只是省去了对本地消息表的操作和轮询发送 MQ 的操作,但实际上两种方案的实现是不一样的 。
消息事务一定要保证业务操作与消息发送的一致性,如果业务操作成功,这条消息也一定投递成功 。

文章插图
消息事务依赖于消息中间件的事务消息,基于消息中间件的二阶段提交实现的,RocketMQ 就支持事务消息 。
执行流程:
- 发送 Prepare 消息到消息中间件 。
- 发送成功后,执行本地事务 。
- 如果事务执行成功,则 Commit,消息中间件将消息下发至消费端 。
- 如果事务执行失败,则回滚,消息中间件将这条 Prepare 消息删除 。
- 消费端接收到消息进行消费,如果消费失败,则不断重试 。
③最大努力通知
最大努力通知相比前两种方案实现简单,适用于一些最终一致性要求较低的业务,比如支付通知,短信通知这种业务 。
以支付通知为例,业务系统调用支付平台进行支付,支付平台进行支付,进行操作支付之后支付平台会尽量去通知业务系统支付操作是否成功,但是会有一个最大通知次数 。
如果超过这个次数后还是通知失败,就不再通知,业务系统自行调用支付平台提供一个查询接口,供业务系统进行查询支付操作是否成功 。
推荐阅读
- 梦见有人要抓我是什么意思 梦见有人要抓我我逃跑
- 梦见睫毛被别人拔了 梦到自己把睫毛拔掉了
- vivo|开机键终于不再“身兼数职”:vivo展示X Fold内外屏3D超声波指纹解锁
- 梦见自己放火是什么征兆 做梦有人故意放火
- 二氧化碳的捕获与应用 日前,科学家发明了一项技术,可以把二氧化碳
- 把PPT转换为Word文档
- 梦见自己用脚把蛇踩死也被蛇咬断手指是什么意思 梦见自己用脚把蛇踩死了,有血
- 有钢圈的文胸把钢圈拆了 内衣钢圈断了还能穿吗
- 喝红茶,把你的胃养起来!
- 适当的喝红茶,会给我们带来健康!
