目录
开始语
一位普通的程序员,慢慢在努力变强!
【Seata】SpringBoot集成Seata1.6-AT模式👈
简介
- 支持XA 事务的数据库。
- Java 应用,通过 JDBC 访问数据库。
1.描述
在 Seata 定义的分布式事务框架内,利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种 事务模式。

- 执行阶段:
- 1.可回滚:业务 SQL 操作放在 XA 分支中进行,由资源对 XA 协议的支持来保证 可回滚
- 2.持久化:XA 分支完成后,执行 XA prepare,同样,由资源对 XA 协议的支持来保证 持久化(即,之后任何意外都不会造成无法回滚的情况)
- 完成阶段:
- 1.分支提交:执行 XA 分支的 commit
- 2.分支回滚:执行 XA 分支的 rollback
2.工作机制
XA 模式 运行在 Seata 定义的事务框架内:

- 执行阶段(E xecute):
- XA start/XA end/XA prepare + SQL + 注册分支
- 完成阶段(F inish):
- XA commit/XA rollback
3.简单总结分析

和AT模式处理相当也是二阶段提交。
第一阶段为准备阶段,TM管理器向TC协调器发送请求,开始注册全局事务,此时RM资源管理器注册分支事务,此时Order和Account两个业务链创建的SQL是未提交的,sql是执行了,但是未提交事务
第二阶段为提交、回滚阶段,当分支事务执行完毕,此时没有任何异常,那么TM管理器就向TC协调器发送一个[commit]提交请求,此时RM资源管理器就需要将事务进行提交处理。如果在一阶段其中某一个分支事务出现异常,那么第二阶段发送的请求就是[rollback],分别将RM中的order、account开始进行回滚。
代码演示
XA的使用和AT的使用是一致的!
1.配置数据源
springboot的@Configuration配置类配置
import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.xa.DataSourceProxyXA;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class OrderXADataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
@Bean("dataSourceProxy")
public DataSource dataSource(DruidDataSource druidDataSource) {
// DataSourceProxy for AT mode
// return new DataSourceProxy(druidDataSource);
// DataSourceProxyXA for XA mode
return new DataSourceProxyXA(druidDataSource);
}
}
application.yml配置文件配置
seata:
data-source-proxy-mode: XA
2.application.yml和nacos服务中的配置
#--------------nacos中的配置
spring:
# staet----------------------------mysql服务配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.233.143:3306/seata_stock?allowMultiQueries=true
username: root
password: getianyu_ROOT_123
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 10
min-idle: 10
maxActive: 200
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
connectionErrorRetryAttempts: 3
breakAfterAcquireFailure: true
timeBetweenConnectErrorMillis: 300000
asyncInit: true
remove-abandoned: false
remove-abandoned-timeout: 1800
transaction-query-timeout: 6000
filters: stat,wall,log4j2
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
web-stat-filter:
enabled: true
url-pattern: "/*"
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
stat-view-servlet:
url-pattern: "/druid/*"
allow:
deny:
reset-enable: false
login-username: admin
login-password: admin
# end----------------------------mysql服务配置
# staet----------------------------mybatis-plus服务配置
mybatis-plus:
global-config:
db-config:
# 逻辑已删除值(默认为 1)
logic-delete-value: 1
# 逻辑未删除值(默认为 0)
logic-not-delete-value: 0
mapper-locations: classpath*:**/repository/xml/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 驼峰,_映射 app_name = appName
map-underscore-to-camel-case: true
# end----------------------------mybatis-plus服务配置
logging:
level:
io.seata: debug
# staet----------------------------seata服务配置
seata:
# 切换XA模式
data-source-proxy-mode: XA
config:
type: nacos
nacos:
server-addr: 192.168.233.180:8848
namespace: seata-server
group: SEATA_GROUP
username: nacos
password: nacos
registry:
type: nacos
nacos:
server-addr: 192.168.233.180:8848
namespace: seata-server
application: seata-server
group: SEATA_GROUP
username: nacos
password: nacos
service:
vgroup-mapping:
default_tx_group: default
disable-global-transaction: false
grouplist:
default: 192.168.233.180:8091
tx-service-group: default_tx_group
# end----------------------------seata服务配置
#--------------application.yml中的配置
server:
port: 9191
spring:
application:
name: stock-service
profiles:
active: @project.active@
cloud:
nacos:
config:
server-addr: @nacos.addr@
namespace: ${spring.profiles.active}
username: nacos
password: nacos
refresh-enabled: true
enabled: true
file-extension: yaml
shared-configs:
- data-id: stock-service-config.yaml
refresh: true
discovery:
server-addr: @nacos.addr@
namespace: ${spring.profiles.active}
watch:
enabled: true
alibaba:
seata:
tx-service-group: default_tx_group
提示:上面只是stock但服务的配置,orders服务的配置和上面一致,不同的是数据库和一些springboot项目的基本信息
3.orders服务的service实现代码
/**
* 下单:创建订单、减库存,涉及到两个服务
*
* @param userId
* @param commodityCode
* @param count
* @param tag commit接口如果入参是[成功],不抛出异常,[失败],抛出异常
*/
@Override
@GlobalTransactional
public void placeOrder(String userId, String commodityCode, Integer count, String tag) {
log.info("OrderService XID = {}", RootContext.getXID());
BigDecimal orderMoney = new BigDecimal(count).multiply(new BigDecimal(5));
Order order = new Order().setUserId(userId).setCommodityCode(commodityCode).setCount(count).setMoney(
orderMoney);
orderDAO.insert(order);
// stock服务未报错,order服务报错
try {
stockFeignClient.deduct(commodityCode, count);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
// 输入commit接口
if ("product-1".equals(commodityCode) && tag.equals("失败")) {
throw new RuntimeException("订单业务处理异常...");
}
}
4.stock服务的service实现代码
/**
* 减库存
*
* @param commodityCode
* @param count
*/
@Transactional(rollbackFor = Exception.class)
public void deduct(String commodityCode, int count) {
log.info("StockService XID = {}", RootContext.getXID());
QueryWrapper<Stock> wrapper = new QueryWrapper<>();
wrapper.setEntity(new Stock().setCommodityCode(commodityCode));
Stock stock = stockDAO.selectOne(wrapper);
stock.setCount(stock.getCount() - count);
stockDAO.updateById(stock);
if (commodityCode.equals("product-2")) {
throw new RuntimeException("异常:模拟业务异常:stock branch exception");
}
}
结果分析
在服务与服务之间调用通过XID的传输实现分布式TM进行管理,不管两个服务之间谁出现异常,那么TM发出的回滚的请求。
1.业务执行成功

双方事务最终都进行commit提交事务操作!
2.业务执行失败

在双方业务执行过程中,服务Order在执行调用Stock之后出现了异常,也就是说,他们两在SQL执行的过程中都没有出现异常,而是在业务代码中出现了异常,此时的rm收到的请求通知是双方进行回滚(rollbacked),从而保证了事务的一致性性。
XA模式的优缺点
优点:
- 基于cp设计,强一致性,不会出现状态不一致的情况
- 二阶段提交成熟、稳定
缺点:
- 执行效率低,基于数据库事务处理,数据容易被锁住,也就是行锁,在简介的过程3中说过,准备阶段是将SQL执行了,但是未提交(高并发慎用)
- 协议阻塞,在XA收到commit或者rollback前必须阻塞等待,如果在短时间内,其中一个全局事务参与者突然出现什么异常,导致一直未提交,此时需要等待超时【回滚】,从而导致性能下降
- 网络波动,也会导致业务的行锁占用使用过长,导致当前行数据无法被使用,从而导致性能下降、业务A的SQL执行,业务B的SQL执行,但是由于B的业务链路很长,导致业务A的SQL行锁占用时间过长,导致RM锁住的资源等待越久,从而导致性能下降
适用场景
低并发、业务数据冲突少(描述:某条数据基本不会被重复执行)的应用程序
本项目代码地址
springboot-seata: springboot整合Seata分布式事务
结束语
本章节完成了,各位正在努力的程序员们,如果你们觉得本文章对您有用的话,你学到了一些东西,希望猿友们点个赞+关注,支持一下猿仁!
持续更新中…