seata实操案例

📅 2026/7/13 21:07:54
seata实操案例
从Docker启动Seata到Spring Boot集成再通过一个订单-库存-账户的电商场景把AT、TCC、SAGA、XA这四种模式的配置和用法都串一遍。一、环境与版本说明以下示例基于Spring Boot 3.2.5 Seata 1.8.0这是官方明确支持Spring Boot 3的组合。如果你用的是Spring Boot 2.xSeata 1.4~1.6也都可以。组件规划Seata ServerTCDocker部署注册到Nacos三个微服务order-service订单、stock-service库存、account-service账户注册中心Nacos 2.3.2数据库MySQL 8.0每个服务有自己的库二、Seata Server Docker部署2.1 拉取并启动临时获取配置dockerpull seataio/seata-server:1.8.0# 临时启动只是为了拷贝配置文件出来dockerrun-d-p8091:8091-p7091:7091--nameseata-temp seataio/seata-server:1.8.0# 拷贝配置到宿主机mkdir-p/docker/seata/configdockercpseata-temp:/seata-server/resources /docker/seata/configdockerrm-fseata-temp2.2 修改配置application.yml关键配置是注册中心和存储模式server:port:7091seata:registry:type:nacosnacos:server-addr:172.17.0.1:8848# 容器内访问宿主机Nacos的IPnamespace:publicgroup:SEATA_GROUPcluster:defaultconfig:type:nacosnacos:server-addr:172.17.0.1:8848namespace:publicgroup:SEATA_GROUPdata-id:seataServer.propertiesstore:mode:db# 生产环境用db测试用file也行db:datasource:druiddb-type:mysqldriver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://172.17.0.1:3306/seata_server?useUnicodetruecharacterEncodingutf8user:rootpassword:1234562.3 正式启动dockerrun-d\--nameseata-server\-p8091:8091\-p7091:7091\-v/docker/seata/config/resources:/seata-server/resources\seataio/seata-server:1.8.0⚠️注意如果用file模式存储事务日志存本地文件Server重启后事务状态会丢失。生产环境务必用db模式。三、Spring Boot 项目集成通用步骤3.1 引入依赖每个微服务的pom.xml都要加!-- Seata Spring Boot Starter --dependencygroupIdio.seata/groupIdartifactIdseata-spring-boot-starter/artifactIdversion1.8.0/version/dependency!-- Spring Cloud Alibaba Seata如果用了Spring Cloud --dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-seata/artifactIdversion2023.0.1.0/versionexclusionsexclusiongroupIdio.seata/groupIdartifactIdseata-spring-boot-starter/artifactId/exclusion/exclusions/dependency!-- Nacos 服务发现 --dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId/dependency这里排除了spring-cloud-starter-alibaba-seata自带的Seata版本用我们指定的1.8.0避免版本冲突。3.2 配置文件application.ymlspring:application:name:order-servicedatasource:url:jdbc:mysql://localhost:3306/order_db?useUnicodetruecharacterEncodingutf8username:rootpassword:123456driver-class-name:com.mysql.cj.jdbc.Driverseata:enabled:trueapplication-id:${spring.application.name}tx-service-group:my_tx_group# 事务组名service:vgroup-mapping:my_tx_group:default# 映射到Seata Server的clusterregistry:type:nacosnacos:server-addr:localhost:8848namespace:publicgroup:SEATA_GROUPconfig:type:nacosnacos:server-addr:localhost:8848namespace:publicgroup:SEATA_GROUPdata-source-proxy-mode:AT# 默认AT也可改为XA关键点tx-service-group要跟Seata Server端配置的vgroupMapping对应上。四、数据库准备AT/XA模式必需AT和XA模式依赖undo_log表每个业务数据库都要创建CREATETABLEundo_log(idBIGINT(20)NOTNULLAUTO_INCREMENT,branch_idBIGINT(20)NOTNULL,xidVARCHAR(100)NOTNULL,contextVARCHAR(128)NOTNULL,rollback_infoLONGBLOBNOTNULL,log_statusINT(11)NOTNULL,log_createdDATETIMENOTNULL,log_modifiedDATETIMENOTNULL,PRIMARYKEY(id),UNIQUEKEYux_undo_log(xid,branch_id))ENGINEInnoDBDEFAULTCHARSETutf8;Seata Server自己的库还需要global_table、branch_table、lock_table三张表从官方GitHub的script/server/db目录获取。五、AT模式最常用无侵入AT模式是Seata的默认模式对业务代码零侵入。5.1 配置application.yml中已设置seata.data-source-proxy-mode: AT默认就是AT不配也行。5.2 代码示例订单服务 - 发起方TMServicepublicclassOrderService{AutowiredprivateStockFeignClientstockFeignClient;AutowiredprivateAccountFeignClientaccountFeignClient;AutowiredprivateOrderMapperorderMapper;GlobalTransactional(namecreate-order,rollbackForException.class)publicvoidcreateOrder(OrderDTOorder){// 1. 本地创建订单orderMapper.insert(order);// 2. 远程扣减库存调用stock-servicestockFeignClient.deductStock(order.getProductId(),order.getQuantity());// 3. 远程扣减账户余额调用account-serviceaccountFeignClient.decreaseBalance(order.getUserId(),order.getAmount());}}库存服务 - 参与方RMServicepublicclassStockService{AutowiredprivateStockMapperstockMapper;// 普通本地事务即可Seata会自动代理DataSourceTransactionalpublicvoiddeductStock(LongproductId,Integerquantity){StockstockstockMapper.selectByProductId(productId);if(stock.getStock()quantity){thrownewRuntimeException(库存不足);}stock.setStock(stock.getStock()-quantity);stockMapper.updateById(stock);}}AT模式原理一阶段执行SQL时自动生成undo_log记录修改前后镜像二阶段如果成功则异步清理undo_log如果失败则根据undo_log自动回滚。六、TCC模式高性能需编码TCC需要手动实现Try预留、Confirm确认、Cancel取消三个方法。6.1 配置seata:data-source-proxy-mode:AT# TCC不需要改这个跟AT共用即可6.2 定义TCC接口LocalTCCpublicinterfaceAccountTCCService{TwoPhaseBusinessAction(namedecreaseBalance,commitMethodconfirm,rollbackMethodcancel)voidtryDecreaseBalance(BusinessActionContextParameter(paramNameuserId)LonguserId,BusinessActionContextParameter(paramNameamount)BigDecimalamount);voidconfirm(BusinessActionContextcontext);voidcancel(BusinessActionContextcontext);}6.3 实现TCC逻辑ServicepublicclassAccountTCCServiceImplimplementsAccountTCCService{AutowiredprivateAccountMapperaccountMapper;OverrideTransactionalpublicvoidtryDecreaseBalance(LonguserId,BigDecimalamount){// Try阶段检查余额并冻结预留资源AccountaccountaccountMapper.selectByUserId(userId);if(account.getBalance().compareTo(amount)0){thrownewRuntimeException(余额不足);}// 将可用余额减少冻结金额增加account.setFrozen(account.getFrozen().add(amount));account.setBalance(account.getBalance().subtract(amount));accountMapper.updateById(account);}OverrideTransactionalpublicvoidconfirm(BusinessActionContextcontext){// Confirm阶段真正扣减释放冻结LonguserIdLong.valueOf(context.getActionContext(userId).toString());BigDecimalamountnewBigDecimal(context.getActionContext(amount).toString());AccountaccountaccountMapper.selectByUserId(userId);account.setFrozen(account.getFrozen().subtract(amount));accountMapper.updateById(account);}OverrideTransactionalpublicvoidcancel(BusinessActionContextcontext){// Cancel阶段回滚释放冻结恢复余额LonguserIdLong.valueOf(context.getActionContext(userId).toString());BigDecimalamountnewBigDecimal(context.getActionContext(amount).toString());AccountaccountaccountMapper.selectByUserId(userId);account.setFrozen(account.getFrozen().subtract(amount));account.setBalance(account.getBalance().add(amount));accountMapper.updateById(account);}}6.4 发起方调用ServicepublicclassOrderService{AutowiredprivateAccountTCCServiceaccountTCCService;GlobalTransactionalpublicvoidcreateOrder(OrderDTOorder){// ... 订单创建 ...// 调用TCC服务accountTCCService.tryDecreaseBalance(order.getUserId(),order.getAmount());}}TCC不依赖数据库事务性能最好但开发成本高适合资金扣减等核心场景。七、SAGA模式长事务流程编排SAGA适合流程长、步骤多的场景通过状态机或注解方式编排正向操作和补偿操作。7.1 引入依赖dependencygroupIdio.seata/groupIdartifactIdseata-saga-starter/artifactIdversion1.8.0/version/dependency7.2 定义状态机JSONresources/statelang/order_saga.json{name:orderSaga,startState:CreateOrder,states:{CreateOrder:{type:ServiceTask,serviceName:orderService,serviceMethod:createOrderLocal,compensateMethod:cancelOrderLocal,next:DeductStock,catch:[{exceptions:[java.lang.Exception],next:Failure}]},DeductStock:{type:ServiceTask,serviceName:stockService,serviceMethod:deductStockLocal,compensateMethod:restoreStockLocal,next:DecreaseBalance,catch:[{exceptions:[java.lang.Exception],next:Failure}]},DecreaseBalance:{type:ServiceTask,serviceName:accountService,serviceMethod:decreaseBalanceLocal,compensateMethod:increaseBalanceLocal,next:Success,catch:[{exceptions:[java.lang.Exception],next:Failure}]},Success:{type:Fail,end:true},Failure:{type:Fail,end:true}}}7.3 发起SAGA事务ServicepublicclassOrderSagaService{AutowiredprivateStateMachineEnginestateMachineEngine;GlobalTransactionalpublicvoidcreateOrder(OrderDTOorder){MapString,ObjectparamsnewHashMap();params.put(order,order);// 启动状态机stateMachineEngine.start(orderSaga,null,params);}}SAGA模式的官方示例可参考 seata-samples 项目。八、XA模式强一致依赖数据库XA模式利用数据库自身的XA协议强一致性但性能较低。8.1 配置seata:data-source-proxy-mode:XA# 改为XA模式8.2 代码跟AT几乎一样ServicepublicclassOrderService{GlobalTransactionalpublicvoidcreateOrder(OrderDTOorder){orderMapper.insert(order);stockFeignClient.deductStock(order.getProductId(),order.getQuantity());accountFeignClient.decreaseBalance(order.getUserId(),order.getAmount());}}XA模式代码跟AT一样无侵入但性能最差锁资源时间长适合对一致性要求极高、并发不高的场景。九、四种模式配置对比模式data-source-proxy-mode额外依赖额外建表代码侵入ATAT默认无undo_log每个业务库无TCCAT或TCC无无高需实现3个方法SAGAATseata-saga-starter无中需定义状态机XAXA无undo_log每个业务库无十、完整Demo参考如果想直接看完整可运行的项目可以参考官方示例seata-samples — 包含各模式的Spring Boot示例社区实战yimo-seata-samples — 同一项目中混合使用AT和TCC模式CSDN教程SpringBoot3.2.5整合Seata1.8.0详细教程 — 完整可运行代码 实操建议先用AT模式跑通代码改动最小快速验证链路遇到锁冲突调大client.rm.lock.retry.timeout参数跨服务XID传递用Feign时spring-cloud-starter-alibaba-seata会自动传递XID不用额外处理生产环境Seata Server至少部署3个节点存储用DB模式