seata 1.2版本分布式事务实战:
一、seata服务端注册并把配置信息配置在nacos配置中心:具体方法请参看这篇,里面同时包含数据库的sql脚本初始化:
1、配置 nacos 成功后
2、启动后注册到配置中心:
二、客户端consume服务创建:
1、、客户端consume相关jar导入:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-nacos-client-consume-7100</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.seata/seata-spring-boot-starter -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-alibaba-seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2、客户端consume注册到nacos配置:bootstrap.yml文件内容:
spring:
cloud:
nacos:
discovery:
server-addr: 172.21.3.158:8849
namespace: 23d0f9d9-096e-4fea-a548-e3ba778a6b83
config: #这里一定记得配置
server-addr: 172.21.3.158:8849
namespace: 23d0f9d9-096e-4fea-a548-e3ba778a6b83
application:
name: consume
#seata相关配置
seata:
enabled: true
application-id: consume
tx-service-group: my_test_tx_group
enable-auto-data-source-proxy: true
use-jdk-proxy: true
config:
type: nacos
nacos:
group: SEATA_GROUP
server-addr: 172.21.3.158:8849
namespace: 23d0f9d9-096e-4fea-a548-e3ba778a6b83
userName: "nacos"
password: "nacos"
registry:
type: nacos
nacos:
application: seata-server
server-addr: 172.21.3.158:8849
namespace: 23d0f9d9-096e-4fea-a548-e3ba778a6b83
userName: "nacos"
password: "nacos"
server:
port: 7100
3、consume核心代码:
import com.nacos.consume.feign.IndexService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
IndexService indexService;
@GlobalTransactional //核心分布式事务注解
public String update(String name) {
String str = indexService.index();//远程调用的业务方法
if(name.equals("nd"))//事务回滚的条件
System.out.println("xxxxxxxxxxxx"+1/0);
return str;
}
}
远程调用的封装接口:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient("provide")
public interface IndexService {
@GetMapping("/index")
public String index();
}
控制层:
import com.nacos.consume.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class IndexController {
@Autowired
ProductService productService;
@GetMapping("index")
public String index(@RequestParam String name){
String result = productService.update(name);//进入业务层
return result;
}
4、启动comsum服务:
三、微服务provide创建:
1、pom导入基本完全一样:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-nacos-client-provide-9100</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.seata/seata-spring-boot-starter -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-alibaba-seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2、核心配置也基本一样:
spring:
application:
name: provide
cloud:
nacos:
discovery:
server-addr: 172.21.3.158:8849
namespace: 23d0f9d9-096e-4fea-a548-e3ba778a6b83
config:
server-addr: 172.21.3.158:8849
namespace: 23d0f9d9-096e-4fea-a548-e3ba778a6b83
#设置feign的超时时间
feign:
client:
config:
default:
connectTimeout: 40000
readTimeout: 40000
#seata相关配置
seata:
enabled: true
application-id: provide
tx-service-group: my_test_tx_group
enable-auto-data-source-proxy: true
use-jdk-proxy: false
config:
type: nacos
nacos:
server-addr: 172.21.3.158:8849
namespace: 23d0f9d9-096e-4fea-a548-e3ba778a6b83
group: SEATA_GROUP
userName: ""
password: ""
registry:
type: nacos
nacos:
application: seata-server
server-addr: 172.21.3.158:8849
namespace: 23d0f9d9-096e-4fea-a548-e3ba778a6b83
userName: ""
password: ""
server:
port: 9100
3、核心代码:
控制层:
import com.nacos.provide.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class IndexController {
@Autowired
StorageService storageService;
@GetMapping("index")
public String index(){
storageService.update();//进入业务层
return 9100+"index";
}
业务层:
import com.nacos.provide.dao.StorageDao;
import com.nacos.provide.service.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class StorageServiceImpl implements StorageService {
@Autowired
StorageDao storageDao;
public void update() {
storageDao.update();//进入dao层操作数据库
}
}
DAO层:
import org.apache.ibatis.annotations.Update;
public interface StorageDao {
@Update("update product set used=used+1")
public int update();
}
数据源配置:
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@MapperScan("com.nacos.provide.dao")
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setPassword("nandao");
dataSource.setUsername("nandao");
dataSource.setUrl("jdbc:postgresql://10.130.16.2466:305188/nan-power?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8");
dataSource.setMaxActive(2000);
dataSource.setMaxWait(20000);
return dataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
return sqlSessionFactoryBean.getObject();
}
}
4、启动成功状态和consume一样。
四、测试接口:
1、发一个正常请求:http://localhost:7100/index?name=ddd
先断点:
seata
客户端:
查看rollback_info 的文本内容方式:
SELECT *,CONVERT (rollback_info USING utf8) as info FROM undo_log;
放开断点后seata 服务端三张表数据和客户端undo_log表数据清空,业务数据成功,执行事务正常提交:
comsume日志:”
provide日志:
2、触发异常请求:http://localhost:7100/index?name=nd
依然断点到这里:
此时服务端和客户端数据库均有数据,业务数据也进行了第一阶段提交。继续往下走,执行结束:
抛异常,事务进行回滚,客户端执行反sql,业务表数据回到了从前;日志如下:
consume日志:
provide服务回滚日志:
实战demo结束,不明白的小伙伴可以留言。