- 搭建 nacos-server docker服务 假设目录在
/docker/docker-compose/nacos
- 1 创建nacos server docker-compose.yml 文件
version: "3.9" services: nacos: image: nacos/nacos-server:v2.2.3 container_name: nacos-standalone-mysql env_file: - ./env/nacos-standlone-mysql.env environment: - NACOS_AUTH_ENABLE=true - NACOS_AUTH_TOKEN_EXPIRE_SECONDS=1800 - NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789 volumes: - ./standalone-logs/:/home/nacos/logs - ./conf/application.properties:/home/nacos/conf/application.properties ports: - "8848:8848" - "9848:9848" depends_on: mysql: condition: service_healthy restart: always mysql: container_name: mysql build: context: . dockerfile: ./image/mysql/8/Dockerfile image: example/mysql:8.0.30 env_file: - ./env/mysql.env volumes: - ./mysql:/var/lib/mysql ports: - "3306:3306" healthcheck: test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ] interval: 5s timeout: 10s retries: 10
- 2 启动 nacos server 进入 /docker/docker-compose/nacos
docker-compose up -d
- 3 访问 nacos server (http://192.168.50.15:8848/nacos) 账号密码都是
nacos
- 4 在nacos上创建seata的命名空间,需要记住的是 命名空间的id ,这个值在后期需要用到。
- 5 运行
nacos-config.sh
导入 seata 的配置到 nacos中对应的命名空间namespace
中 主要是db
部分 - 6 官方导入脚本代码
- 7 我用官方脚本导入报错。 107行的配置数据,我参考脚本用postman自己手动一条一条导入的。。。
#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html #Transport configuration, for client and server transport.type=TCP transport.server=NIO transport.heartbeat=true transport.enableTmClientBatchSendRequest=false transport.enableRmClientBatchSendRequest=true transport.enableTcServerBatchSendResponse=false transport.rpcRmRequestTimeout=30000 transport.rpcTmRequestTimeout=30000 transport.rpcTcRequestTimeout=30000 transport.threadFactory.bossThreadPrefix=NettyBoss transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler transport.threadFactory.shareBossWorker=false transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector transport.threadFactory.clientSelectorThreadSize=1 transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread transport.threadFactory.bossThreadSize=1 transport.threadFactory.workerThreadSize=default transport.shutdown.wait=3 transport.serialization=seata transport.compressor=none #Transaction routing rules configuration, only for the client service.vgroupMapping.default_tx_group=default #If you use a registry, you can ignore it service.default.grouplist=192.168.50.15:8091 service.enableDegrade=false service.disableGlobalTransaction=false #Transaction rule configuration, only for the client client.rm.asyncCommitBufferLimit=10000 client.rm.lock.retryInterval=10 client.rm.lock.retryTimes=30 client.rm.lock.retryPolicyBranchRollbackOnConflict=true client.rm.reportRetryCount=5 client.rm.tableMetaCheckEnable=true client.rm.tableMetaCheckerInterval=60000 client.rm.sqlParserType=druid client.rm.reportSuccessEnable=false client.rm.sagaBranchRegisterEnable=false client.rm.sagaJsonParser=fastjson client.rm.tccActionInterceptorOrder=-2147482648 client.tm.commitRetryCount=5 client.tm.rollbackRetryCount=5 client.tm.defaultGlobalTransactionTimeout=60000 client.tm.degradeCheck=false client.tm.degradeCheckAllowTimes=10 client.tm.degradeCheckPeriod=2000 client.tm.interceptorOrder=-2147482648 client.undo.dataValidation=true client.undo.logSerialization=jackson client.undo.onlyCareUpdateColumns=true server.undo.logSaveDays=7 server.undo.logDeletePeriod=86400000 client.undo.logTable=undo_log client.undo.compress.enable=true client.undo.compress.type=zip client.undo.compress.threshold=64k #For TCC transaction mode tcc.fence.logTableName=tcc_fence_log tcc.fence.cleanPeriod=1h #Log rule configuration, for client and server log.exceptionRate=100 #Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional. store.mode=db store.lock.mode=file store.session.mode=file #Used for password encryption store.publicKey= #If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block. store.file.dir=file_store/data store.file.maxBranchSessionSize=16384 store.file.maxGlobalSessionSize=512 store.file.fileWriteBufferCacheSize=16384 store.file.flushDiskMode=async store.file.sessionReloadReadSize=100 #These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block. store.db.datasource=druid store.db.dbType=mysql store.db.driverClassName=com.mysql.cj.jdbc.Driver store.db.url=jdbc:mysql://192.168.50.15:3306/seata_dev?rewriteBatchedStatements=true&&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false store.db.user=root store.db.password=root store.db.minConn=5 store.db.maxConn=50 store.db.globalTable=global_table store.db.branchTable=branch_table store.db.distributedLockTable=distributed_lock store.db.queryLimit=100 store.db.lockTable=lock_table store.db.maxWait=5000 #These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block. store.redis.mode=single store.redis.single.host=127.0.0.1 store.redis.single.port=6379 store.redis.sentinel.masterName= store.redis.sentinel.sentinelHosts= store.redis.maxConn=10 store.redis.minConn=1 store.redis.maxTotal=100 store.redis.database=0 store.redis.password= store.redis.queryLimit=100 #Transaction rule configuration, only for the server server.recovery.committingRetryPeriod=1000 server.recovery.asynCommittingRetryPeriod=1000 server.recovery.rollbackingRetryPeriod=1000 server.recovery.timeoutRetryPeriod=1000 server.maxCommitRetryTimeout=-1 server.maxRollbackRetryTimeout=-1 server.rollbackRetryTimeoutUnlockEnable=false server.distributedLockExpireTime=10000 server.xaerNotaRetryTimeout=60000 server.session.branchAsyncQueueSize=5000 server.session.enableBranchAsyncRemove=false server.enableParallelRequestHandle=false #Metrics configuration, only for the server metrics.enabled=false metrics.registryType=compact metrics.exporterList=prometheus metrics.exporterPrometheusPort=9898
- 搭建 seata-server docker服务 假设目录在
/docker/docker-compose/seata
- 1 为了复制要修改的配置目录 先用docker run 启动一个默认的seata-server
- 2 启动一个临时seata server ,复制要修改的资源目录
# docker run -d -rm --name seata-temp seataio/seata-server:1.6.1 docker cp seata-temp:/seata-server/resources /docker/docker-compose/seata/resources
- 3 参考
/docker/docker-compose/seata/resources/application.example.yml
修改seata-server 配置文件/docker/docker-compose/seata/resources/application.yml
server: port: 7091 spring: application: name: seata-server logging: config: classpath:logback-spring.xml file: path: ${user.home}/logs/seata extend: logstash-appender: destination: 127.0.0.1:4560 kafka-appender: bootstrap-servers: 127.0.0.1:9092 topic: logback_to_logstash console: user: username: seata password: seata seata: config: # support: nacos, consul, apollo, zk, etcd3 type: nacos nacos: server-addr: 192.168.50.15:8848 namespace: 82eca4a8-ef2f-488e-9ebd-cb70bb2f060a group: SEATA_GROUP username: nacos password: nacos context-path: ##if use MSE Nacos with auth, mutex with username/password attribute #access-key: #secret-key: data-id: seata.properties registry: # support: nacos, eureka, redis, zk, consul, etcd3, sofa type: nacos nacos: application: seata-server server-addr: 192.168.50.15:8848 group: SEATA_GROUP namespace: 82eca4a8-ef2f-488e-9ebd-cb70bb2f060a cluster: default username: nacos password: nacos context-path: ##if use MSE Nacos with auth, mutex with username/password attribute #access-key: #secret-key: store: # support: file 、 db 、 redis mode: db db: datasource: druid db-type: mysql driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.50.15:3306/seata_dev?rewriteBatchedStatements=true&&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false user: root password: root min-conn: 10 max-conn: 100 global-table: global_table branch-table: branch_table lock-table: lock_table distributed-lock-table: distributed_lock query-limit: 1000 max-wait: 5000 server: service-port: 8091 #If not configured, the default is '${server.port} + 1000' security: secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017 tokenValidityInMilliseconds: 1800000 ignore: urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login
- 4 停止临时的seata-temp
docker stop seata-temp
- 5 创建 seata server docker-compose.yml
version: "3.9" services: seata-server: image: seataio/seata-server:1.6.1 hostname: seata-server ports: - "7091:7091" - "8091:8091" environment: # 时区设置为东8区 - TZ=Asia/Shanghai # 可不用, 会从配置中心读取, 加上这个万一配置中心配置有问题加载不到配置时会报错可提前发现问题 - STORE_MODE=db # 以SEATA_IP作为host注册到注册中心,使用宿主机ip - SEATA_IP=192.168.50.15 - SEATA_PORT=8091 # 官方说明的registry.conf 貌似是不生效的 至少我测试了很久1.61的seata docker是这样 我映射这个的话 启动会一直报127的mysql连接失败不知道为什么官方文档也不统一 而且不能只映射application.yml一个文件 得映射整个文件夹 - - #- SEATA_CONFIG_NAME=file:/root/seata-config/registry volumes: # 时区设置为东8区 上面的环境变量有时不生效 - /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime - ./resources:/seata-server/resources
- 6 启动 seata server 进入/docker/docker-compose/seata 运行
docker-compose up -d
- 访问 seata server (http://192.168.50.15:7091/#/TransactionInfo) 账号密码都是
seata
- 初始化项目sql
不同的业务表理论上来说是在不同的库中的, 可以一个服务建一个库。 你也可以先放一个库开发测试。
请注意每个使用seata-server
的微服务的数据库都必须得有undo_log
表!
-- ----------------------------
-- Table structure for t_account
-- ----------------------------
DROP TABLE IF EXISTS `t_account`;
CREATE TABLE `t_account`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`amount` double(14, 2
) DEFAULT '0.00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_account
-- ----------------------------
INSERT INTO `t_account`
VALUES ('1', '1', '4000.00');
-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_no` varchar(255) DEFAULT NULL,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT '0',
`amount` double(14, 2
) DEFAULT '0.00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_order
-- ----------------------------
-- ----------------------------
-- Table structure for t_stock
-- ----------------------------
DROP TABLE IF EXISTS `t_stock`;
CREATE TABLE `t_stock`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_stock
-- ----------------------------
INSERT INTO `t_stock`
VALUES ('1', 'C202306121800', '水杯', '1000');
-- ----------------------------
-- Table structure for undo_log
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
-- ----------------------------
DROP TABLE IF EXISTS `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;
请求前 DB 数据如下
t_account
表数据
id | user_id | account |
---|---|---|
1 | 1 | 4000 |
t_account
表数据
id | commodity_code | name | count |
---|---|---|---|
1 | C202306121800 | 水杯 | 1000 |
t_order
表无数据生成
- 启动 微服务 的 business account stock order
- 访问 nacos 检查 当前的服务是否都正确注册到 nacos server
- GET 请求 http://127.0.0.1/business/toOrder?userId=1&commodityCode=C202306121800&count=2000&amount=4000
@RestController
@RequestMapping("/business")
public class BusinessController {
@Resource
private OrderFeign orderFeign;
@Resource
private StockFeign stockFeign;
@Resource
private AccountFeign accountFeign;
@GlobalTransactional
@RequestMapping("/toOrder")
public void toOrder (String userId, String commodityCode, Integer count, BigDecimal amount) {
accountFeign.reduce(userId, amount);
stockFeign.deduct(commodityCode, count);
orderFeign.add(userId, commodityCode, count, amount);
}
}
2023-06-12 18:29:06.317 INFO 33872 --- [p-nio-80-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-06-12 18:29:06.317 INFO 33872 --- [p-nio-80-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2023-06-12 18:29:06.317 INFO 33872 --- [p-nio-80-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
2023-06-12 18:29:06.347 INFO 33872 --- [p-nio-80-exec-1] io.seata.tm.TransactionManagerHolder : TransactionManager Singleton io.seata.tm.DefaultTransactionManager@606d2bad
2023-06-12 18:29:06.383 INFO 33872 --- [p-nio-80-exec-1] i.seata.tm.api.DefaultGlobalTransaction : Begin new global transaction [192.168.50.15:8091:18416337030565889]
2023-06-12 18:29:07.216 INFO 33872 --- [p-nio-80-exec-1] i.seata.tm.api.DefaultGlobalTransaction : Suspending current transaction, xid = 192.168.50.15:8091:18416337030565889
2023-06-12 18:29:07.217 INFO 33872 --- [p-nio-80-exec-1] i.seata.tm.api.DefaultGlobalTransaction : [192.168.50.15:8091:18416337030565889] rollback status: Rollbacked
2023-06-12 18:29:07.229 ERROR 33872 --- [p-nio-80-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.FeignException$InternalServerError: [500] during [GET] to [http://stock/stock/deduct?commodityCode=C202306121800&count=2000] [StockFeign#deduct(String,Integer)]: [{"timestamp":"2023-06-12T10:29:07.147+00:00","status":500,"error":"Internal Server Error","path":"/stock/deduct"}]] with root cause
feign.FeignException$InternalServerError: [500] during [GET] to [http://stock/stock/deduct?commodityCode=C202306121800&count=2000] [StockFeign#deduct(String,Integer)]: [{"timestamp":"2023-06-12T10:29:07.147+00:00","status":500,"error":"Internal Server Error","path":"/stock/deduct"}]
at feign.FeignException.serverErrorStatus(FeignException.java:250) ~[feign-core-11.10.jar:na]
at feign.FeignException.errorStatus(FeignException.java:197) ~[feign-core-11.10.jar:na]
at feign.FeignException.errorStatus(FeignException.java:185) ~[feign-core-11.10.jar:na]
...
2023-06-12 18:29:06.494 INFO 8076 --- [p-nio-81-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-06-12 18:29:06.494 INFO 8076 --- [p-nio-81-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2023-06-12 18:29:06.495 INFO 8076 --- [p-nio-81-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@46fda57c] was not registered for synchronization because synchronization is not active
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.baomidou.mybatisplus.core.toolkit.SetAccessibleAction (file:/D:/WORK/apache-maven-REPO/com/baomidou/mybatis-plus-core/3.5.3.1/mybatis-plus-core-3.5.3.1.jar) to field java.lang.invoke.SerializedLambda.capturingClass
WARNING: Please consider reporting this to the maintainers of com.baomidou.mybatisplus.core.toolkit.SetAccessibleAction
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@7ad2c4a1] will not be managed by Spring
==> Preparing: SELECT id,user_id,amount FROM t_account WHERE (user_id = ?)
==> Parameters: 1(String)
<== Columns: id, user_id, amount
<== Row: 1, 1, 4000.0
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@46fda57c]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@435cfb65] was not registered for synchronization because synchronization is not active
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@45e34ff] will not be managed by Spring
original SQL: UPDATE t_account SET user_id=?,
amount=? WHERE id=?
SQL to parse, SQL: UPDATE t_account SET user_id=?,
amount=? WHERE id=?
parse the finished SQL: UPDATE t_account SET user_id = ?, amount = ? WHERE id = ?
==> Preparing: UPDATE t_account SET user_id=?, amount=? WHERE id=?
==> Parameters: 1(String), 0.0(BigDecimal), 1(Integer)
<== Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@435cfb65]
2023-06-12 18:29:07.174 INFO 8076 --- [h_RMROLE_1_1_32] i.s.c.r.p.c.RmBranchRollbackProcessor : rm handle branch rollback process:xid=192.168.50.15:8091:18416337030565889,branchId=18416337030565890,branchType=AT,resourceId=jdbc:mysql://192.168.50.15:3306/seata_account,applicationData=null
2023-06-12 18:29:07.176 INFO 8076 --- [h_RMROLE_1_1_32] io.seata.rm.AbstractRMHandler : Branch Rollbacking: 192.168.50.15:8091:18416337030565889 18416337030565890 jdbc:mysql://192.168.50.15:3306/seata_account
2023-06-12 18:29:07.207 INFO 8076 --- [h_RMROLE_1_1_32] i.s.r.d.undo.AbstractUndoLogManager : xid 192.168.50.15:8091:18416337030565889 branch 18416337030565890, undo_log deleted with GlobalFinished
2023-06-12 18:29:07.208 INFO 8076 --- [h_RMROLE_1_1_32] io.seata.rm.AbstractRMHandler : Branch Rollbacked result: PhaseTwo_Rollbacked
JDBC Connection [io.seata.rm.datasource.ConnectionProxy@51d520a6] will not be managed by Spring
==> Preparing: SELECT id,name,commodity_code,count FROM t_stock WHERE (commodity_code = ?)
==> Parameters: C202306121800(String)
<== Columns: id, name, commodity_code, count
<== Row: 1, 水杯, C202306121800, 1000
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@47dd5002]
2023-06-12 18:29:07.139 ERROR 34704 --- [p-nio-83-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: Not enough stock] with root cause
java.lang.RuntimeException: Not enough stock
at com.blankhang.stock.service.impl.StockServiceImpl.deduce(StockServiceImpl.java:42) ~[classes/:na]
at com.blankhang.stock.service.impl.StockServiceImpl$$FastClassBySpringCGLIB$$f693087.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.23.jar:5.3.23]
...
seata-seata-server-1 | 18:29:06.381 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : timeout=60000,transactionName=toOrder(java.lang.String, java.lang.String, java.lang.Integer, java.math.BigDecimal),clientIp:192.168.50.2,vgroup:default_tx_group
seata-seata-server-1 | 18:29:06.408 INFO --- [rverHandlerThread_1_5_500] i.s.s.coordinator.DefaultCoordinator : Begin new global transaction applicationId: business,transactionServiceGroup: default_tx_group, transactionName: toOrder(java.lang.String, java.lang.String, java.lang.Integer, java.math.BigDecimal),timeout:60000,xid:192.168.50.15:8091:18416337030565889
seata-seata-server-1 | 18:29:06.835 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : SeataMergeMessage xid=192.168.50.15:8091:18416337030565889,branchType=AT,resourceId=jdbc:mysql://192.168.50.15:3306/seata_account,lockKey=t_account:1
seata-seata-server-1 | ,clientIp:192.168.50.2,vgroup:default_tx_group
seata-seata-server-1 | 18:29:06.857 INFO --- [rverHandlerThread_1_6_500] i.seata.server.coordinator.AbstractCore : Register branch successfully, xid = 192.168.50.15:8091:18416337030565889, branchId = 18416337030565890, resourceId = jdbc:mysql://192.168.50.15:3306/seata_account ,lockKeys = t_account:1
seata-seata-server-1 | 18:29:07.196 INFO --- [ batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler : xid=192.168.50.15:8091:18416337030565889,extraData=null,clientIp:192.168.50.2,vgroup:default_tx_group
seata-seata-server-1 | 18:29:07.240 INFO --- [rverHandlerThread_1_7_500] io.seata.server.coordinator.DefaultCore : Rollback branch transaction successfully, xid = 192.168.50.15:8091:18416337030565889 branchId = 18416337030565890
seata-seata-server-1 | 18:29:07.241 INFO --- [rverHandlerThread_1_7_500] io.seata.server.coordinator.DefaultCore : Rollback global transaction successfully, xid = 192.168.50.15:8091:18416337030565889.
请求后 DB 数据如下
t_account
表数据
id | user_id | account |
---|---|---|
1 | 1 | 4000 |
t_account
表数据
id | commodity_code | name | count |
---|---|---|---|
1 | C202306121800 | 水杯 | 1000 |
t_order
表无数据生成
通过服务日志、seata-server日志、db 可以发现,seata提示事务全局回滚成功, db 数据未修改,到此分布式事务完成。
在使用seata后 如果要使用分布式事务,只需要在入口方法中加上@GlobalTransactional
注解即可。
如果要结合本地事务一起使用的话,本地的事务只能被
@GlobalTransactional
注解内的方法包含, 否则会导致分布式事务失败!
下面是正确用法
public class test {
@Resource
private FeignA feignA;
@Resource
private FeignB feignB;
@GlobalTransactional
public void startGlobalTX(){
feignA.doSomething();
txLocal();
feignB.doSomething();
}
@Transactional
public void txLocal(){
System.out.println('local tx...');
}
}
下面是错误用法
public class test {
@Resource
private FeignA feignA;
@Resource
private FeignB feignB;
@Transactional
public void txLocal(){
startGlobalTX();
System.out.println('local tx...');
}
@GlobalTransactional
public void startGlobalTX(){
feignA.doSomething();
feignB.doSomething();
}
}
参考来源
Seata安装与使用 https://www.cnblogs.com/wt20/p/17158267.html
docker-compose 部署 Seata Server
官方文档