1. seata安装
- docker 安装
docker run --name seata-server \ -p 8091:8091 \ -p 7091:7091 \ -e SEATA_IP=192.168.0.250 \ -e SEATA_PORT=8091 \ seataio/seata-server
- 将安装好的配置文件数据,拷贝一份到物理机
docker cp seata-serve:/seata-server/resources /User/seata/config
- 修改配置文件
server: port: 7091 spring: application: name: seata-server logging: config: classpath:logback-spring.xml file: path: ${log.home:${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.0.250:8848 namespace: 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: seataServer.properties registry: # support: nacos, eureka, redis, zk, consul, etcd3, sofa type: nacos nacos: application: seata-server server-addr: 192.168.0.250:8848 group: SEATA_GROUP namespace: cluster: default username: nacos password: nacos context-path: store: # support: file 、 db 、 redis mode: db db: datasource: druid db-type: mysql driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.0.250:3306/seata-work?rewriteBatchedStatements=true # 配置数据库服务端地址,提前初始化SQL user: root password: mysql_xMYB44 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 security: secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017 tokenValidityInMilliseconds: 1800000 ignore: urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login
- 删除旧的seata-server,重新安装,并进行路径映射
docker run --name seata-server \ -p 8091:8091 \ -p 7091:7091 \ -e SEATA_IP=192.168.0.250 \ -e SEATA_PORT=8091 \ -v /User/seata/config:/seata-server/resources \ seataio/seata-server
2. 数据库初始化
- 客户端
LS0g5rOo5oSP5q2k5aSEMC4zLjArIOWinuWKoOWUr+S4gOe0ouW8lSB1eF91bmRvX2xvZwpDUkVBVEUgVEFCTEUgYHVuZG9fbG9nYCAoCiAgYGlkYCBiaWdpbnQoMjApIE5PVCBOVUxMIEFVVE9fSU5DUkVNRU5ULAogIGBicmFuY2hfaWRgIGJpZ2ludCgyMCkgTk9UIE5VTEwsCiAgYHhpZGAgdmFyY2hhcigxMDApIE5PVCBOVUxMLAogIGBjb250ZXh0YCB2YXJjaGFyKDEyOCkgTk9UIE5VTEwsCiAgYHJvbGxiYWNrX2luZm9gIGxvbmdibG9iIE5PVCBOVUxMLAogIGBsb2dfc3RhdHVzYCBpbnQoMTEpIE5PVCBOVUxMLAogIGBsb2dfY3JlYXRlZGAgZGF0ZXRpbWUgTk9UIE5VTEwsCiAgYGxvZ19tb2RpZmllZGAgZGF0ZXRpbWUgTk9UIE5VTEwsCiAgYGV4dGAgdmFyY2hhcigxMDApIERFRkFVTFQgTlVMTCwKICBQUklNQVJZIEtFWSAoYGlkYCksCiAgVU5JUVVFIEtFWSBgdXhfdW5kb19sb2dgIChgeGlkYCxgYnJhbmNoX2lkYCkKKSBFTkdJTkU9SW5ub0RCIEFVVE9fSU5DUkVNRU5UPTEgREVGQVVMVCBDSEFSU0VUPXV0Zjg7
- 服务端
LS0gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gVGhlIHNjcmlwdCB1c2VkIHdoZW4gc3RvcmVNb2RlIGlzICdkYicgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KLS0gdGhlIHRhYmxlIHRvIHN0b3JlIEdsb2JhbFNlc3Npb24gZGF0YQpDUkVBVEUgVEFCTEUgSUYgTk9UIEVYSVNUUyBgZ2xvYmFsX3RhYmxlYAooCiAgICBgeGlkYCAgICAgICAgICAgICAgICAgICAgICAgVkFSQ0hBUigxMjgpIE5PVCBOVUxMLAogICAgYHRyYW5zYWN0aW9uX2lkYCAgICAgICAgICAgIEJJR0lOVCwKICAgIGBzdGF0dXNgICAgICAgICAgICAgICAgICAgICBUSU5ZSU5UICAgICAgTk9UIE5VTEwsCiAgICBgYXBwbGljYXRpb25faWRgICAgICAgICAgICAgVkFSQ0hBUigzMiksCiAgICBgdHJhbnNhY3Rpb25fc2VydmljZV9ncm91cGAgVkFSQ0hBUigzMiksCiAgICBgdHJhbnNhY3Rpb25fbmFtZWAgICAgICAgICAgVkFSQ0hBUigxMjgpLAogICAgYHRpbWVvdXRgICAgICAgICAgICAgICAgICAgIElOVCwKICAgIGBiZWdpbl90aW1lYCAgICAgICAgICAgICAgICBCSUdJTlQsCiAgICBgYXBwbGljYXRpb25fZGF0YWAgICAgICAgICAgVkFSQ0hBUigyMDAwKSwKICAgIGBnbXRfY3JlYXRlYCAgICAgICAgICAgICAgICBEQVRFVElNRSwKICAgIGBnbXRfbW9kaWZpZWRgICAgICAgICAgICAgICBEQVRFVElNRSwKICAgIFBSSU1BUlkgS0VZIChgeGlkYCksCiAgICBLRVkgYGlkeF9zdGF0dXNfZ210X21vZGlmaWVkYCAoYHN0YXR1c2AgLCBgZ210X21vZGlmaWVkYCksCiAgICBLRVkgYGlkeF90cmFuc2FjdGlvbl9pZGAgKGB0cmFuc2FjdGlvbl9pZGApCikgRU5HSU5FID0gSW5ub0RCCiAgREVGQVVMVCBDSEFSU0VUID0gdXRmOG1iNDsKCi0tIHRoZSB0YWJsZSB0byBzdG9yZSBCcmFuY2hTZXNzaW9uIGRhdGEKQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgYGJyYW5jaF90YWJsZWAKKAogICAgYGJyYW5jaF9pZGAgICAgICAgICBCSUdJTlQgICAgICAgTk9UIE5VTEwsCiAgICBgeGlkYCAgICAgICAgICAgICAgIFZBUkNIQVIoMTI4KSBOT1QgTlVMTCwKICAgIGB0cmFuc2FjdGlvbl9pZGAgICAgQklHSU5ULAogICAgYHJlc291cmNlX2dyb3VwX2lkYCBWQVJDSEFSKDMyKSwKICAgIGByZXNvdXJjZV9pZGAgICAgICAgVkFSQ0hBUigyNTYpLAogICAgYGJyYW5jaF90eXBlYCAgICAgICBWQVJDSEFSKDgpLAogICAgYHN0YXR1c2AgICAgICAgICAgICBUSU5ZSU5ULAogICAgYGNsaWVudF9pZGAgICAgICAgICBWQVJDSEFSKDY0KSwKICAgIGBhcHBsaWNhdGlvbl9kYXRhYCAgVkFSQ0hBUigyMDAwKSwKICAgIGBnbXRfY3JlYXRlYCAgICAgICAgREFURVRJTUUoNiksCiAgICBgZ210X21vZGlmaWVkYCAgICAgIERBVEVUSU1FKDYpLAogICAgUFJJTUFSWSBLRVkgKGBicmFuY2hfaWRgKSwKICAgIEtFWSBgaWR4X3hpZGAgKGB4aWRgKQopIEVOR0lORSA9IElubm9EQgogIERFRkFVTFQgQ0hBUlNFVCA9IHV0ZjhtYjQ7CgotLSB0aGUgdGFibGUgdG8gc3RvcmUgbG9jayBkYXRhCkNSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIGBsb2NrX3RhYmxlYAooCiAgICBgcm93X2tleWAgICAgICAgIFZBUkNIQVIoMTI4KSBOT1QgTlVMTCwKICAgIGB4aWRgICAgICAgICAgICAgVkFSQ0hBUigxMjgpLAogICAgYHRyYW5zYWN0aW9uX2lkYCBCSUdJTlQsCiAgICBgYnJhbmNoX2lkYCAgICAgIEJJR0lOVCAgICAgICBOT1QgTlVMTCwKICAgIGByZXNvdXJjZV9pZGAgICAgVkFSQ0hBUigyNTYpLAogICAgYHRhYmxlX25hbWVgICAgICBWQVJDSEFSKDMyKSwKICAgIGBwa2AgICAgICAgICAgICAgVkFSQ0hBUigzNiksCiAgICBgc3RhdHVzYCAgICAgICAgIFRJTllJTlQgICAgICBOT1QgTlVMTCBERUZBVUxUICcwJyBDT01NRU5UICcwOmxvY2tlZCAsMTpyb2xsYmFja2luZycsCiAgICBgZ210X2NyZWF0ZWAgICAgIERBVEVUSU1FLAogICAgYGdtdF9tb2RpZmllZGAgICBEQVRFVElNRSwKICAgIFBSSU1BUlkgS0VZIChgcm93X2tleWApLAogICAgS0VZIGBpZHhfc3RhdHVzYCAoYHN0YXR1c2ApLAogICAgS0VZIGBpZHhfYnJhbmNoX2lkYCAoYGJyYW5jaF9pZGApLAogICAgS0VZIGBpZHhfeGlkYCAoYHhpZGApCikgRU5HSU5FID0gSW5ub0RCCiAgREVGQVVMVCBDSEFSU0VUID0gdXRmOG1iNDsKCkNSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIGBkaXN0cmlidXRlZF9sb2NrYAooCiAgICBgbG9ja19rZXlgICAgICAgIENIQVIoMjApIE5PVCBOVUxMLAogICAgYGxvY2tfdmFsdWVgICAgICBWQVJDSEFSKDIwKSBOT1QgTlVMTCwKICAgIGBleHBpcmVgICAgICAgICAgQklHSU5ULAogICAgcHJpbWFyeSBrZXkgKGBsb2NrX2tleWApCikgRU5HSU5FID0gSW5ub0RCCiAgREVGQVVMVCBDSEFSU0VUID0gdXRmOG1iNDsKCklOU0VSVCBJTlRPIGBkaXN0cmlidXRlZF9sb2NrYCAobG9ja19rZXksIGxvY2tfdmFsdWUsIGV4cGlyZSkgVkFMVUVTICgnQXN5bmNDb21taXR0aW5nJywgJyAnLCAwKTsKSU5TRVJUIElOVE8gYGRpc3RyaWJ1dGVkX2xvY2tgIChsb2NrX2tleSwgbG9ja192YWx1ZSwgZXhwaXJlKSBWQUxVRVMgKCdSZXRyeUNvbW1pdHRpbmcnLCAnICcsIDApOwpJTlNFUlQgSU5UTyBgZGlzdHJpYnV0ZWRfbG9ja2AgKGxvY2tfa2V5LCBsb2NrX3ZhbHVlLCBleHBpcmUpIFZBTFVFUyAoJ1JldHJ5Um9sbGJhY2tpbmcnLCAnICcsIDApOwpJTlNFUlQgSU5UTyBgZGlzdHJpYnV0ZWRfbG9ja2AgKGxvY2tfa2V5LCBsb2NrX3ZhbHVlLCBleHBpcmUpIFZBTFVFUyAoJ1R4VGltZW91dENoZWNrJywgJyAnLCAwKTs=
3. Pom配置
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <exclusions> <exclusion> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> </exclusion> </exclusions> </dependency> <!-- 若版本加载不出来,则单独添加 --> <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>1.7.1</version> </dependency>
4. seata配置
# 配置seata seata: enabled: true tx-service-group: xiaoqiu_tx_group # 事务组 service: vgroup-mapping: xiaoqiu_tx_group: SEATA_GROUP # 事务组映射 grouplist: SEATA_GROUP: 192.168.0.250:8091 # seata ip地址 config: nacos: server-addr: 192.168.0.250:8848 username: nacos password: nacos registry: nacos: server-addr: 192.168.0.250:8848 username: nacos password: nacos
5. 自动回滚
直接把原有的@Transactional 替换成@GlobalTransactional 即可
1. 当**本机发生异常,且未被全局异常处理器捕获时**,即可直接回滚; 2. 当**外部调用发生异常时,返回的状态码非200**,也可以直接回滚。
6. 手动回滚
外部异常,但返回状态码还是200
调用外部接口时,外部接口自己捕获了异常,此时返回的http状态码为200,不会自动回滚,需要根据返回的数据单独判断,并进行手动回滚。
举例:
// 初始化简历 R<Void> r = workResumeServiceFeign.init(user.getId()); // 如果调用状态不是200,则手动回滚全局事务 if (r.getStatus() != HttpStatusEnum.SUCCESS.getCode()) { String xid = RootContext.getXID(); if (StringUtils.isNotBlank(xid)) { try { GlobalTransactionContext.reload(xid).rollback(); } catch (TransactionException e) { log.error("createUsers, 回滚全局事务失败! mobile: {}", mobile, e); } finally { GraceException.display(ResponseStatusEnum.USER_REGISTER_ERROR); } } }
本地异常,但异常被全局异常捕获
此时本地发生了异常,但是由于优雅处理异常的全局异常处理类,把异常吃掉了,所以需要单独处理。此时可以加一个AOP切面,对方法进行包装,手动的拦截要全局事务包裹的类,然后手动回滚异常。
举例:
异常代码:
@GlobalTransactional @Override public Users createUsers(String mobile) { Users user = getDefaultUsers(mobile); user.setMobile(mobile); usersMapper.insert(user);
// 初始化简历 workResumeServiceFeign.init(user.getId()); // 模拟除0异常 int a = 1 / 0; return user; }
切面:
@Slf4j @Component @Aspect public class SeataTransactionAspect {
/** * 调用service之前,手动加入或者创建全局事务 */ @Before("execution(* com.xiaoqiu.service.impl.UsersServiceImpl.createUsers(..))") public void beginTransaction(JoinPoint joinPoint) throws TransactionException { log.info("手动开启全局事务"); // 手动开启全局事务 GlobalTransaction gt = GlobalTransactionContext.getCurrentOrCreate(); gt.begin(); }
/** * 捕获异常,则手动回滚全局事务 */ @AfterThrowing( throwing = "throwable", pointcut = "execution(* com.xiaoqiu.service.impl.UsersServiceImpl.createUsers(..))" ) public void seataRollback(Throwable throwable) throws Throwable { log.warn("捕获到异常信息,则回滚,异常信息为:{}", throwable.getMessage());
// 从当前线程获得xid String xid = RootContext.getXID(); if (StringUtils.isNotBlank(xid)) { GlobalTransactionContext.reload(xid).rollback(); } } }
|