分布式事务

问题描述

  1. 远程调用服务成功,但是没有返回结果

    导致:订单回滚了,但是远程服务已经实现了

  2. 远程调用服务之后的流程出现异常

    但是已执行的远程调用不能回滚

事务传播

本地事务失效问题

同一个对象内,事务方法不能互相调用。因为绕过了代理对象。

解决

使用代理对象调用事务

  1. 开启动态代理,对外暴露代理对象
@EnableAspectJAutoProxy(exposeProxy = true)
  1. 使用动态代理调用本地事务

分布式事务解决方案一: SEATA

AT模式(全局锁):

  1. 创建 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,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  1. 安装
  2. 使用 seata DataSourceProxy代理自己的数据源
  3. 在每个微服务中导入 .conf
  4. 在分布式大事务入口标注 @GlobalTransactional
  5. 在远程调用的小事务标注 @Transactional

分布式事务解决方案二:可靠消息 + 最终一致性

  • 业务处理服务在业务事务提交之前,向实时消息服务请求发送消息,实时消息服务只记录消息数据,而不是真正的发送。
  • 业务处理服务在业务事务提交之后,向实时消息服务确认发送。
  • 只有在得到确认发送指令后,实时消息服务才会真正发送。