1.启动seata-server
简介:本文采用docker部署方式,采用file的配置方式,也可以使用nacos 注册中心,这里为了讲解功能使用,就简化了注册中心环节。
docker-compose.yml
version: "3"
services:
seata-server:
image: seataio/seata-server
hostname: seata-server
container_name: seata-server
ports:
- "8091:8091"
environment:
- SEATA_PORT=8091
volumes:
- ./config:/root/seata-config
registry.conf
registry {
type = "file"
file {
name = "file.conf"
}
}
config {
type = "file"
file {
name = "file.conf"
}
}
file.conf
service {
vgroup_mapping.tx_group = "default"
default.grouplist = "127.0.0.1:8091"
disableGlobalTransaction = false
}
store {
mode = "file"
file {
dir = "sessionStore"
}
}
tx_group 自定义服务组名,这里的client的group名一定要和server的group一致,不然分布式事务无法生效。
启动成功
2.创建数据库
起另一台服务器
创建db_order 数据库,端口号3336
version: '3.1'
services:
db_order:
image: mysql
container_name: db_order
environment:
MYSQL_ROOT_PASSWORD: 123456
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=true
ports:
- 3336:3306
volumes:
- ./data:/var/lib/mysql
创建db_order_item数据库,端口号3346
version: '3.1'
services:
db_order_item:
image: mysql
container_name: db_order_item
environment:
MYSQL_ROOT_PASSWORD: 123456
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=true
ports:
- 3346:3306
volumes:
- ./data:/var/lib/mysql
3. 创建数据库表结构
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;
创建表tb_order
CREATE TABLE tb_order (
id bigint NOT NULL AUTO_INCREMENT,
order_id bigint DEFAULT NULL,
user_id bigint DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
创建表tb_order_item
CREATE TABLE tb_order_item (
id bigint NOT NULL AUTO_INCREMENT,
user_id bigint DEFAULT NULL,
order_id bigint DEFAULT NULL,
order_item_id bigint DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
4.创建工程
完整的demo 已上传github 地址:https://github.com/liangzhe9/spring-alibaba-seata
1.创建主工程pom
hello-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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.devin</groupId>
<artifactId>hello-seata</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>dependencies</module>
<module>commons</module>
<module>business</module>
<module>provider</module>
</modules>
<properties>
<skipTests>true</skipTests>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.devin</groupId>
<artifactId>dependencies</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2. 创建dependencies module
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.devin</groupId>
<artifactId>dependencies</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>dependencies</name>
<packaging>pom</packaging>
<properties>
<dubbo.version>2.7.4.1</dubbo.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
<spring-cloud-alibaba.verion>2.1.1.RELEASE</spring-cloud-alibaba.verion>
<spring-boot-mapper.version>2.1.5</spring-boot-mapper.version>
<spring-boot-pagehelper.version>1.2.13</spring-boot-pagehelper.version>
<alibaba-seata.version>1.0.0</alibaba-seata.version>
<alibaba-spring-context-support.version>1.0.5</alibaba-spring-context-support.version>
<okhttp3.version>4.2.2</okhttp3.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.verion}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Apache Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-kryo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
<version>${alibaba-spring-context-support.version}</version>
</dependency>
<!-- Alibaba Seata -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>${alibaba-seata.version}</version>
</dependency>
<!-- Others -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${spring-boot-mapper.version}</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${spring-boot-pagehelper.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp3.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestone</id>
<name>Spring Milestone</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshot</id>
<name>Spring Snapshot</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestone</id>
<name>Spring Milestone</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshot</id>
<name>Spring Snapshot</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
3. 创建common module
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>
<parent>
<groupId>com.devin</groupId>
<artifactId>commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>commons-mapper</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- Datasource -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<!-- Others -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
创建MyMapper 继承tk mybatis的mapper
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {
}
4. 创建provider RPC dubbo提供者 module
<modules>
<module>provider-order-api</module>
<module>provider-order-item-api</module>
<module>provider-transaction-api</module>
<module>provider-order-service</module>
<module>provider-order-item-service</module>
<module>provider-transaction-service</module>
</modules>
provider-order-item-api 开放对外item相关interface
provider-order-item-service 处理item表数据,api的具体实现
provider-order-api 开放对外order相关interface
provider-order-service 处理order表数据,api的具体实现
provider-transaction-api 暴露对外dubbo api
provider-transaction-service 同时处理order、item两个业务service
package com.devin.spring.cloud.alibaba.provider.service.impl;
import com.devin.spring.cloud.alibaba.provider.domain.TbOrder;
import com.devin.spring.cloud.alibaba.provider.domain.TbOrderItem;
import com.devin.spring.cloud.alibaba.provider.service.api.ProviderTransactionService;
import com.devin.spring.cloud.alibaba.provider.service.api.TbOrderItemService;
import com.devin.spring.cloud.alibaba.provider.service.api.TbOrderService;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
@Service(version = "1.0.0")
public class ProviderTransactionServiceImpl implements ProviderTransactionService {
@Reference(version = "1.0.0")
private TbOrderService tbOrderService;
@Reference(version = "1.0.0")
private TbOrderItemService TbOrderItemService;
@Override
@GlobalTransactional
public void createOrder(TbOrder order, TbOrderItem item) {
tbOrderService.insert(order);
TbOrderItemService.insert(item);
if (order.getUserId().equals(2L)) {
throw new RuntimeException("seata has exception.");
}
}
}
这里简单处理了,当用户userId = 2L 的时候,直接抛出异常,触发事务,进行回滚
application.yml
spring:
application:
name: provider-transaction
cloud:
nacos:
discovery:
server-addr: 192.168.6.162:8848
sentinel:
transport:
enable: true
port: 8720
dashboard: localhost:8081
alibaba:
seata:
tx-service-group: tx-group
dubbo:
scan:
base-packages: com.devin.spring.cloud.alibaba.provider.service
protocol:
name: dubbo
port: -1
provider:
loadbalance: roundrobin
registry:
address: nacos://192.168.6.162:8848
5. 创建business controller web服务 module
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>
<parent>
<groupId>com.devin</groupId>
<artifactId>business</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>business-transaction-service</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Apache Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- Projects -->
<dependency>
<groupId>com.devin</groupId>
<artifactId>provider-transaction-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.devin.spring.cloud.alibaba.business.BusinessTransactionApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
application:
name: business-transaction
cloud:
nacos:
discovery:
server-addr: 192.168.6.162:8848
sentinel:
transport:
port: 8722
dashboard: localhost:8081
dubbo:
scan:
base-packages: com.devin.spring.cloud.alibaba.business.controller
protocol:
name: dubbo
port: -1
provider:
loadbalance: roundrobin
registry:
address: nacos://192.168.6.162:8848
server:
port: 12001
management:
endpoints:
web:
exposure:
include: "*"
controller
package com.devin.spring.cloud.alibaba.business.controller;
import com.devin.spring.cloud.alibaba.provider.domain.TbOrder;
import com.devin.spring.cloud.alibaba.provider.domain.TbOrderItem;
import com.devin.spring.cloud.alibaba.provider.service.api.ProviderTransactionService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "transaction")
public class BusinessTransactionController {
@Reference(version = "1.0.0")
ProviderTransactionService providerTransactionService;
@GetMapping(value = "create/order")
public String createOrder() {
TbOrder order = new TbOrder();
order.setOrderId(1L);
order.setUserId(2L);
TbOrderItem orderItem = new TbOrderItem();
orderItem.setUserId(2L);
orderItem.setOrderId(1L);
orderItem.setOrderItemId(1L);
providerTransactionService.createOrder(order, orderItem);
return "ok";
}
}
运行结果
tb_order_item表
tb_order表
访问web项目http://localhost:12001/transaction/create/order
触发异常
seata-server log如下,Rollback global transaction successfuly
ProviderOrderApplication
ProviderItemApplication
回滚成功