seatra的AT模式
seata框架的使用
1、在common模块导入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
注意seata默认引入的是1.1的版本,客户端与服务的版本需要一致才行,因此需要用下面的方法引入依赖。
<!--seata包的引入-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-springboot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
2、在各个微服务模块中配置
seata:
# 事务的分组
tx-service-group: ${spring.application.name}-group
service:
grouplist:
# seata所在的地址
xclass: 127.0.0.1:8091
vgroup-mapping:
class-user-service-group: xclass
需要用到分布式事务的地方:
用户注册----> 发放优惠券
两个分别属于 user模块和coupon模块
此时关闭了全局异常,否则异常会被吞掉,然后任然认为是成功的。
@Override
//@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
@GlobalTransactional //开启分布式事务
public JsonData register(UserRegisterRequest registerRequest)
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
public JsonData initNewUserCoupon(NewUserCouponRequest newUserCouponRequest)
但是通过不能直接这么使用,不然事务回滚需要用户重新注册,引起不便。
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;
其中的rollback_info 会保留阶段1 和阶段2 的内容,包含before image 和after image 的内容,以及阶段二的是否回滚还是提交的记录
全局异常的时候分布式事务的解决方案:
private void userRegisterInitTask(UserDO userDO){
NewUserCouponRequest request = new NewUserCouponRequest();
request.setName(userDO.getName());
request.setUserId(userDO.getId());
// 调用coupon微服务中的方法
JsonData jsonData = couponFeignService.addNewUserCoupon(request);
// 因为配置了全局异常,因此需要重新检查是否发送了异常且被吞掉,判断后全局分布式事务中任然可以使用
if(jsonData.getCode()!=0){
throw new RuntimeException("发放优惠券异常");
}
log.info("发放新用户注册优惠券:{},结果:{}",request.toString(),jsonData.toString());
}