上篇文章讲了如何安装seata,这篇文章主要讲如何使用,分布讲解什么情况回滚,不回滚
一、新建父级maven
pom.xml文件导入
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>nacosprovider</groupId>
<artifactId>minenacos</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>nacosprovider</module>
<module>consumer</module>
<module>alibabaconfig</module>
<module>nacosprovidertwo</module>
</modules>
<properties>
<spring-cloud-starter-alibaba-nacos-discovery.version>2.2.0.RELEASE</spring-cloud-starter-alibaba-nacos-discovery.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<!--<scope>provided</scope>-->
<!--<version>${spring-cloud-starter-alibaba-nacos-discovery.version}</version>-->
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<!--<version>1.2.0-beta.1</version>-->
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.11</version>
</dependency>
</dependencies>
</project>
二、整合nacos服务提供者
接着上篇文章的代码,加入mybatis和feign
目录结构
pom.xml导入了seata
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>nacosprovider</groupId>
<artifactId>minenacos</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath/>
</parent>
<groupId>com.apiprovider</groupId>
<artifactId>nacosprovider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>nacosprovider</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-data-jpa</artifactId>-->
<!--<version>2.2.5.RELEASE</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>2.3.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>6</source>
<target>6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
启动类
package com.apiprovider.nacosprovider;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.apiprovider.nacosprovider.Mapper")//使用MapperScan批量扫描所有的Mapper接口;
@EnableFeignClients //feigin扫描
public class NacosproviderApplication {
public static void main(String[] args) {
SpringApplication.run(NacosproviderApplication.class, args);
}
}
其中usercontroller代码
package com.apiprovider.nacosprovider.Controller;
import com.apiprovider.nacosprovider.Entity.User;
import com.apiprovider.nacosprovider.Service.UserService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sun.nio.ch.ThreadPool;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
IUserCreateService UserCreateService;
@RequestMapping("/findAll")
public List<User> findAll(){
return userService.findAll();
}
@RequestMapping("/getUserByID")
public User getUserByID(Integer id){
return userService.getUserByID(id);
}
@RequestMapping("/CreateUser")
@GlobalTransactional(name = "my_test_tx_group",rollbackFor = Exception.class)
public void CreateUser(User user) throws Exception
{
userService.CreateUser(user);
String name = user.getUsername()+"111111";
user.setUsername(name);
UserCreateService.CreateUser(user);
}
@RequestMapping("/DeleteUser")
public void DeleteUser(Integer id)
{
userService.DeleteUser(id);
}
@RequestMapping("/UpdateUser")
public void UpdateUser(User user)
{
userService.UpdateUser(user);
}
}
@GlobalTransactional(name = "my_test_tx_group",rollbackFor = Exception.class)注解作用为开启seata事务
新增application.yml
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: service-provider
#数据库连接配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.0.10:3306/test?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true
username: root
password: piaost123
server:
port: 4444
#mybatis的相关配置
mybatis:
#mapper配置文件
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.apiprovider.nacosprovider.Entity
#开启驼峰命名
configuration:
map-underscore-to-camel-case: true
seata:
enabled: true
# 应用 id 为唯一便于区分
application-id: order
# 事务分组,这个是默认分组
tx-service-group: my_test_tx_group
config:
type: nacos
nacos:
namespace:
serverAddr: 127.0.0.1:8848
group: SEATA_GROUP
username: ""
password: ""
cluster: default
registry:
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group : DEFAULT_GROUP
namespace:
username: ""
password: ""
cluster: default
此时需要,往你数据库中新增一张表,安装Seata时提供的
注解:
tx-service-group: my_test_tx_group为
config下的group为注册再nacos中的group
registry的配置来源也是安装时的配置
三、复制第二个服务,新建成第三个
只修改applicaiton.yml
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: service-providertwo
#数据库连接配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.0.10:3306/test?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true
username: root
password: piaost123
server:
port: 4445
#mybatis的相关配置
mybatis:
#mapper配置文件
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.nacosprovidertwo.nacosprovidertwo.Entity
#开启驼峰命名
configuration:
map-underscore-to-camel-case: true
seata:
enabled: true
# 应用 id 为唯一便于区分
application-id: order
# 事务分组,这个是默认分组
tx-service-group: my_test_tx_group
config:
type: nacos
nacos:
namespace:
serverAddr: 127.0.0.1:8848
group: SEATA_GROUP
username: ""
password: ""
cluster: default
registry:
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group : DEFAULT_GROUP
namespace:
username: ""
password: ""
cluster: default
和usercontroller
package com.nacosprovidertwo.nacosprovidertwo.Controller;
import com.nacosprovidertwo.nacosprovidertwo.Entity.User;
import com.nacosprovidertwo.nacosprovidertwo.Service.UserService;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/findAll")
public List<User> findAll(){
return userService.findAll();
}
@RequestMapping("/getUserByID")
public User getUserByID(Integer id){
return userService.getUserByID(id);
}
@RequestMapping("/CreateUser")
@GlobalTransactional(name = "my_test_tx_group",rollbackFor = Exception.class)
public void CreateUser(@RequestBody User user) throws Exception
{
userService.CreateUser(user);
throw new Exception("分布式事务回滚");
}
@RequestMapping("/DeleteUser")
public void DeleteUser(Integer id)
{
userService.DeleteUser(id);
}
@RequestMapping("/UpdateUser")
public void UpdateUser(User user)
{
userService.UpdateUser(user);
}
}
ok,到此位置搭建完毕
开始启动服务
NacosproviderApplication,
NacosprovidertwoApplication
当前在第二个服务手动抛了异常
此时数据库为空
使用postman发送数据请求服务1
实现预期效果,服务二抛出异常
此时数据被回滚
为再次确认,我们去掉第二个手动抛异常的代码,预测新增两条数据
请求后正常返回
再看数据库正常新增了两条数据,此时初步实现了seata管理分布式事务
我们去掉第二个服务中的事务注解试一下会不会回滚,此时清空数据库,注释注解,抛出异常
在此纠正一个问题:除了发起时需要添加注解@GlobalTransactional,被调服务只要添加Transactional即可
再次启动服务
如期,抛出异常,再看数据库
很明显第二条没有回滚掉,说明不加事务回滚注解,是不行的
初步认知到此为止,在实验的过程中我发现个问题,第一次启动时,请求,第一个服务插入一条数据(没问题),但是第二个服务会往数据库插入两条相同的数据
如:我们重启服务,清空数据库,不抛异常
此时请求,返回成功
我们去看数据库
发现第二个服务执行了两次,初步怀疑,第一个服务请求了两次,这个问题 留到下个文章解决