分布式事务实践(SeataSpringBoot)
#头条创作挑战赛#版本: Springboot:2.2.0 SpringCloud: 2020.0.3 Seata: 1.4
本文章demo地址:https://gitee.com/TZWw/springboot-nacos-seata14 1.下载seata
1)地址:http://seata.io/zh-cn/blog/download.html
2)在conf文件夹修改file.conf文件
3)向本地数据库导入seata需要的表 创建名字为seata的数据库 新建表branch_table、global_table、lock_table CREATE TABLE `branch_table` ( `branch_id` bigint NOT NULL, `xid` varchar(128) NOT NULL, `transaction_id` bigint DEFAULT NULL, `resource_group_id` varchar(32) DEFAULT NULL, `resource_id` varchar(256) DEFAULT NULL, `lock_key` varchar(128) DEFAULT NULL, `branch_type` varchar(8) DEFAULT NULL, `status` tinyint DEFAULT NULL, `client_id` varchar(64) DEFAULT NULL, `application_data` varchar(2000) DEFAULT NULL, `gmt_create` datetime DEFAULT NULL, `gmt_modified` datetime DEFAULT NULL, PRIMARY KEY (`branch_id`), KEY `idx_xid` (`xid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;CREATE TABLE `global_table` ( `xid` varchar(128) NOT NULL, `transaction_id` bigint DEFAULT NULL, `status` tinyint NOT NULL, `application_id` varchar(32) DEFAULT NULL, `transaction_service_group` varchar(32) DEFAULT NULL, `transaction_name` varchar(128) DEFAULT NULL, `timeout` int DEFAULT NULL, `begin_time` bigint DEFAULT NULL, `application_data` varchar(2000) DEFAULT NULL, `gmt_create` datetime DEFAULT NULL, `gmt_modified` datetime DEFAULT NULL, PRIMARY KEY (`xid`), KEY `idx_gmt_modified_status` (`gmt_modified`,`status`), KEY `idx_transaction_id` (`transaction_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;CREATE TABLE `lock_table` ( `row_key` varchar(128) NOT NULL, `xid` varchar(96) DEFAULT NULL, `transaction_id` mediumtext, `branch_id` mediumtext, `resource_id` varchar(256) DEFAULT NULL, `table_name` varchar(32) DEFAULT NULL, `pk` varchar(36) DEFAULT NULL, `gmt_create` datetime DEFAULT NULL, `gmt_modified` datetime DEFAULT NULL, PRIMARY KEY (`row_key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
4)修改registry.conf文件
5)将seata配置信息添加到nacos配置中心 1.启动本地的nacos服务
2.下载config.txt和nacos-config.sh两个文件
https://github.com/seata/seata/blob/develop/script/config-center/config.txt
https://github.com/seata/seata/blob/develop/script/config-center/nacos/nacos-config.sh
3.然后执行nacos-config.sh脚本
4.查看nacos中添加成功的配置
6)启动seata
进入bin目录下,执行 ./seata-server.sh 出现下图即为启动成功
2. 服务间调用(服务one调用服务two)
1) 创建one和two数据库,每个数据库都必须包含undo_log表 one数据库 CREATE TABLE `count` ( `id` int NOT NULL AUTO_INCREMENT, `count` int DEFAULT NULL COMMENT "库存", PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb3; CREATE TABLE `undo_log` ( `id` bigint NOT NULL AUTO_INCREMENT, `branch_id` bigint NOT NULL, `xid` varchar(100) NOT NULL, `context` varchar(128) NOT NULL, `rollback_info` longblob NOT NULL, `log_status` int NOT NULL, `log_created` datetime NOT NULL, `log_modified` datetime NOT NULL, `ext` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb3;two数据库 CREATE TABLE `order` ( `id` int NOT NULL AUTO_INCREMENT, `order_count` int DEFAULT NULL, `product_id` bigint DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb3; CREATE TABLE `undo_log` ( `id` bigint NOT NULL AUTO_INCREMENT, `branch_id` bigint NOT NULL, `xid` varchar(100) NOT NULL, `context` varchar(128) NOT NULL, `rollback_info` longblob NOT NULL, `log_status` int NOT NULL, `log_created` datetime NOT NULL, `log_modified` datetime NOT NULL, `ext` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3;
创建one和two服务
此处省略创建服务过程…
maven父工程依赖 <?xml version="1.0" encoding="UTF-8"?> 4.0.0 pom serviceone servicetwo servicecommon org.springframework.boot spring-boot-starter-parent 2.5.5 com.example demo2 0.0.1-SNAPSHOT demo2 Demo project for Spring Boot 1.8 2020.0.3 2021.1 com.alibaba druid 1.1.9 org.springframework.boot spring-boot-starter-test 2.3.3.RELEASE test org.mybatis.spring.boot mybatis-spring-boot-starter 2.2.0 org.springframework.cloud spring-cloud-context 2.2.3.RELEASE org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies 2021.1 pom import mysql mysql-connector-java 8.0.26 pom import org.springframework.boot spring-boot-starter-log4j 1.3.8.RELEASE org.springframework.boot spring-boot-maven-plugin org.projectlombok lombok one服务:
bootstrap.yml文件 # Spring spring: application: # 应用名称 name: service-one profiles: # 环境配置 active: dev main: allow-bean-definition-overriding: true cloud: nacos: discovery: # 服务注册地址 server-addr: localhost:8848 # namespace: 3d25ad9f-6b5a-4f1a-a4a7-0bbba90a00fa group: SEATA_GROUP config: # 配置中心地址 server-addr: localhost:8848 namespace: 8221aa53-c648-4c6a-8a41-0c3a685ba58e # # 配置文件格式 file-extension: yml # # 共享配置 # shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} # seata: tx-service-group: my_test_tx_group registry: type: nacos nacos: server-addr: ${spring.cloud.nacos.discovery.server-addr} group: ${spring.cloud.nacos.discovery.group} # namespace: 6c990727-93b2-4081-a8c6-6b015c56eda2 config: type: nacos nacos: server-addr: ${spring.cloud.nacos.discovery.server-addr} group: ${spring.cloud.nacos.discovery.group} # namespace: 6db428d4-e7a3-4dd3-be02-283960e0e704 service: vgroup-mapping: my_test_tx_group: default
nacos中one的配置(service-one-dev.yml): # Spring spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/service-one?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: 123456789 server: port: 8085 # Mybatis配置 mybatis: # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath:mapper/**/*.xml httpclient: enabled: true
one服务依赖 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.mybatis.spring.boot mybatis-spring-boot-starter com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config org.springframework.cloud spring-cloud-loadbalancer org.springframework.cloud spring-cloud-starter-bootstrap org.springframework.cloud spring-cloud-context 3.0.2 mysql mysql-connector-java org.springframework.cloud spring-cloud-starter-openfeign 2.2.3.RELEASE cn.hutool hutool-all 5.6.6 com.alibaba druid-spring-boot-starter 1.2.6 org.springframework.boot spring-boot-starter-log4j com.alibaba.cloud spring-cloud-starter-alibaba-seata io.github.openfeign feign-httpclient
controller : @GetMapping("/insertOpt") public CommonResult insertOpt() { try { countService.insertOpt(); return new CommonResult(true, "成功", null); } catch (Exception e) { return new CommonResult(false, "失败", null); } }
serviceImpl @Override @GlobalTransactional(rollbackFor = Exception.class, name = "insertOpt") public CommonResult insertOpt() { Count count = new Count(); count.setCount(12); int insert = this.countDao.insert(count); if (insert == 0) { throw new RuntimeException("first失败"); } Order order = new Order(); order.setOrderCount(12); order.setProductId(12L); CommonResult commonResult = remoteServiceTwo.insertOne(order); if (!commonResult.getBool()){ throw new RuntimeException("操作远程失败!"); } Map map = new HashMap<>(16); map.put("count", insert); map.put("order", commonResult); System.err.println("map===="+ map.toString()); return new CommonResult(true, "成功", map); }
feign请求 @FeignClient(value = "service-two") public interface RemoteServiceTwo { @PostMapping("/order/insertOne") public CommonResult insertOne(Order order); }two服务
bootstrap.yml # Spring spring: application: # 应用名称 name: service-two profiles: # 环境配置 active: dev main: allow-bean-definition-overriding: true cloud: nacos: discovery: # 服务注册地址 server-addr: localhost:8848 # namespace: 3d25ad9f-6b5a-4f1a-a4a7-0bbba90a00fa group: SEATA_GROUP config: # 配置中心地址 server-addr: localhost:8848 namespace: 8221aa53-c648-4c6a-8a41-0c3a685ba58e # # 配置文件格式 file-extension: yml # # 共享配置 # shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} seata: tx-service-group: my_test_tx_group registry: type: nacos nacos: server-addr: ${spring.cloud.nacos.discovery.server-addr} group: ${spring.cloud.nacos.discovery.group} # namespace: 6c990727-93b2-4081-a8c6-6b015c56eda2 config: type: nacos nacos: server-addr: ${spring.cloud.nacos.discovery.server-addr} group: ${spring.cloud.nacos.discovery.group} service: vgroup-mapping: my_test_tx_group: default
pom.xml 依赖 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.mybatis.spring.boot mybatis-spring-boot-starter com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config org.springframework.cloud spring-cloud-loadbalancer org.springframework.cloud spring-cloud-starter-bootstrap org.springframework.cloud spring-cloud-context 3.0.2 mysql mysql-connector-java org.springframework.cloud spring-cloud-starter-openfeign 2.2.3.RELEASE cn.hutool hutool-all 5.6.6 com.example servicecommon 0.0.1-SNAPSHOT com.alibaba druid-spring-boot-starter 1.2.6 org.springframework.boot spring-boot-starter-log4j com.alibaba.cloud spring-cloud-starter-alibaba-seata
nacos中two服务的配置service-two-dev.yml # Spring spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/service-two?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: 123456789 server: port: 8086 # Mybatis配置 mybatis: # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath:mapper/**/*.xml # 我使用的这个版本这一步可以忽略 httpclient: enabled: true
two服务controller @PostMapping("insertOne") public CommonResult selectOne(@RequestBody Order order) { try { this.orderService.insert(order); return new CommonResult(true, "成功", null); } catch (Exception e) { StaticLog.error("失败:======{}", e); return new CommonResult(false, "失败", null); } }
serviceImpl /** * 新增数据 * * @param order 实例对象 * @return 实例对象 */ @Override public Order insert(Order order) { // int a = 1/0; // 此处是为了出现错误,看seata是否会回滚 this.orderDao.insert(order); return order; }3. 查看结果插入成功操作
浏览器操作
serviceone的日志
servicetwo日志
数据库结果-插入成功 (清空数据库进行插入失败操作)
插入失败操作 1) 插入失败,进行回滚---在servicetwo业务代码上添加一个报错代码
浏览器操作
serviceone 日志(进行了回滚)
servicetwo 日志
数据库数据
4.成功
我是Tz,想把我遇到的问题告诉你