在微服务架构的设计理念中,每个微服务拥有独立的专属数据库是核心设计原则,能够实现服务与数据的解耦。但跨多个独立数据库的业务操作,会引发分布式事务问题:无法通过传统本地事务保证多个数据库操作的原子性(要么全部成功,要么全部失败)。
以电子商务系统为案例,用户创建订单的流程包含两个核心操作:
订单服务向订单数据库写入订单数据
库存服务向库存数据库扣减商品库存
两个操作分布在不同的数据库中,必须在同一个分布式事务中执行,确保数据最终一致性。
创建根目录 sca-service 统一管理业务微服务,内部包含两个核心子模块:
sca-service-order:订单服务(服务消费者,调用库存服务)
sca-service-stock:库存服务(服务提供者,提供库存扣减接口)
项目基于 Spring Boot 3 构建,使用统一的依赖管理模块管控版本,核心依赖版本如下:
在 sca-dependencies\pom.xml 追加
<properties>
<mybatis-plus.version>3.5.15</mybatis-plus.version>
</properties>在公共依赖模块统一引入:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>使用 Docker 部署两个相互隔离的 MySQL 8 实例,分别对应订单服务、库存服务。
在 sca-service/order 目录下创建 docker-compose.yml 配置文件:
services:
mysql:
image: mysql:8.0.30
container_name: mysql-order
restart: always
volumes:
- ./data/mysql/data:/var/lib/mysql
environment:
- TZ=Asia/Shanghai
- 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=1
ports:
- 3307:3306执行 SQL 初始化数据库和表(数据库名使用下划线规范,避免横杠语法异常):
-- 创建数据库
CREATE DATABASE sca_order DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
USE sca_order;
-- 订单表
CREATE TABLE `t_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`product_id` int(11) DEFAULT NULL,
`count` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);注意:连接订单数据库时,端口为 3307,为独立隔离的数据库实例

在 sca-service/stock 目录下创建 docker-compose.yml 配置文件:
services:
mysql:
image: mysql:8.0.30
container_name: mysql-stock
restart: always
volumes:
- ./data/mysql/data:/var/lib/mysql
environment:
- TZ=Asia/Shanghai
- 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=1
ports:
- 3308:3306执行 SQL 初始化数据库、表和测试数据:
-- 创建数据库
CREATE DATABASE sca_stock DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
USE sca_stock;
-- 库存表
CREATE TABLE `t_stock` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) DEFAULT NULL,
`count` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
-- 初始化测试数据:商品 1 的库存为 100
INSERT INTO t_stock (product_id, `count`) VALUES (1, 100);注意:连接库存数据库时,端口为 3308,为独立隔离的数据库实例

在 sca-service 模块下创建 sca-service-stock 库存微服务,作为服务提供者。
核心 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lusifer</groupId>
<artifactId>sca-service</artifactId>
<version>${revision}</version>
</parent>
<artifactId>sca-service-stock</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>库存服务</description>
<dependencies>
<!-- Web 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 服务治理 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 数据持久化 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<!-- 工具类 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 分布式事务 Seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>在 sca-service 模块下创建 sca-service-order 订单微服务,作为服务消费者。
核心 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lusifer</groupId>
<artifactId>sca-service</artifactId>
<version>${revision}</version>
</parent>
<artifactId>sca-service-order</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>订单服务</description>
<dependencies>
<!-- Web 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 远程调用 + 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- 服务治理 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 数据持久化 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<!-- 工具类 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 分布式事务 Seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>