以下是在 Spring Boot 中整合 Seata AT 模式、PostgreSQL 和 MyBatis 实现分布式事务的完整配置和示例:
1. 项目结构
src/
├── main/
│ ├── java/
│ │ └── com/example/
│ │ ├── config/ # 配置类
│ │ │ └── SeataConfig.java
│ │ ├── mapper/ # MyBatis Mapper接口
│ │ │ └── OrderMapper.java
│ │ ├── model/ # 实体类
│ │ │ └── Order.java
│ │ ├── service/ # 服务层
│ │ │ └── OrderService.java
│ │ └── Application.java # 启动类
│ └── resources/
│ ├── mapper/ # MyBatis XML
│ │ └── OrderMapper.xml
│ ├── application.yml # 配置文件
│ └── seata.conf # Seata 配置(可选)
2. 依赖配置(pom.xml)
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- PostgreSQL 驱动 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!-- Seata -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.5.2</version>
</dependency>
</dependencies>
3. Seata Server 配置
-
下载 Seata Server: Seata GitHub Release 下载并解压。
-
配置 Seata Server(
conf/registry.conf):registry { type = "nacos" # 使用 Nacos 作为注册中心 nacos { serverAddr = "localhost:8848" namespace = "" cluster = "default" } } config { type = "nacos" # 使用 Nacos 作为配置中心 nacos { serverAddr = "localhost:8848" namespace = "" group = "SEATA_GROUP" } } -
启动 Seata Server:
sh bin/seata-server.sh -p 8091 -h 0.0.0.0
4. Spring Boot 应用配置
(1) application.yml(核心配置)
spring:
application:
name: order-service
datasource:
url: jdbc:postgresql://localhost:5432/order_db
username: postgres
password: 123456
driver-class-name: org.postgresql.Driver
# Seata 配置
seata:
enabled: true
application-id: order-service
tx-service-group: my-tx-group # 事务组名(需与 Seata Server 一致)
service:
vgroup-mapping:
my-tx-group: default # 事务组映射到 Seata Server 集群
grouplist:
default: 127.0.0.1:8091 # Seata Server 地址
registry:
type: nacos # 注册中心类型
nacos:
server-addr: localhost:8848
config:
type: nacos # 配置中心类型
(2) Seata 数据源代理配置
@Configuration
public class SeataConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new DruidDataSource();
}
// 代理数据源(关键:Seata 通过代理数据源管理事务)
@Bean
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
// MyBatis 使用代理数据源
@Bean
public SqlSessionFactory sqlSessionFactory(DataSourceProxy dataSourceProxy) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSourceProxy);
factoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/*.xml")
);
return factoryBean.getObject();
}
}
5. MyBatis Mapper 与实体类
(1) 实体类 Order.java
public class Order {
private Long id;
private Long userId;
private BigDecimal amount;
// Getters/Setters
}
(2) Mapper 接口 OrderMapper.java
@Mapper
public interface OrderMapper {
@Insert("INSERT INTO orders(user_id, amount) VALUES(#{userId}, #{amount})")
void insertOrder(Order order);
}
(3) Mapper XML OrderMapper.xml
<mapper namespace="com.example.mapper.OrderMapper">
<insert id="insertOrder" parameterType="com.example.model.Order">
INSERT INTO orders(user_id, amount)
VALUES(#{userId}, #{amount})
</insert>
</mapper>
6. 服务层与全局事务
(1) 开启全局事务(@GlobalTransactional)
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
// 全局事务注解
@GlobalTransactional(name = "createOrder", rollbackFor = Exception.class)
public void createOrder(Order order) {
orderMapper.insertOrder(order); // 本地事务
// 调用其他微服务(如扣减库存服务)
restTemplate.postForEntity("http://inventory-service/deduct", order.getProductId(), Void.class);
}
}
(2) 回滚测试
@SpringBootTest
public class OrderServiceTest {
@Autowired
private OrderService orderService;
@Test
public void testGlobalRollback() {
Order order = new Order();
order.setUserId(1L);
order.setAmount(new BigDecimal("100.00"));
try {
orderService.createOrder(order);
} catch (Exception e) {
// 验证数据库是否无数据插入
}
}
}
7. PostgreSQL 表结构调整
确保数据库表包含 UNDO_LOG(Seata AT 模式需要):
-- 在 PostgreSQL 中创建 UNDO_LOG 表
CREATE TABLE undo_log (
id SERIAL PRIMARY KEY,
branch_id BIGINT NOT NULL,
xid VARCHAR(100) NOT NULL,
context VARCHAR(128) NOT NULL,
rollback_info BYTEA NOT NULL,
log_status INT NOT NULL,
log_created TIMESTAMP NOT NULL,
log_modified TIMESTAMP NOT NULL
);
-- 业务表 orders
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id BIGINT,
amount DECIMAL(10,2)
);
8. 注意事项
- Seata 对 PostgreSQL 的支持: Seata AT 模式原生支持 MySQL,PostgreSQL 需要手动创建
UNDO_LOG表,并确保驱动兼容性。 - 代理数据源: 必须通过
DataSourceProxy包装原生数据源,否则事务无法拦截。 - Nacos 配置: 确保 Seata Server 和 Spring Boot 应用使用相同的 Nacos 配置中心。
- 全局事务 ID(XID)传递: 在微服务间调用时,需通过请求头传递
XID(如使用SeataRestTemplateInterceptor)。
总结
通过以上步骤,Spring Boot 应用可以:
- 集成 Seata AT 模式:通过
@GlobalTransactional注解管理分布式事务。 - 兼容 PostgreSQL:手动创建
UNDO_LOG表,配置数据源代理。 - 结合 MyBatis:通过代理数据源实现 SQL 拦截和回滚日志记录。