二、数据持久化篇(深度增强版)
2.1 JDBC Template深度解析
架构设计思想
graph LR
A[DataSource] --> B[JdbcTemplate]
B --> C[执行SQL]
C --> D[处理结果集]
D --> E[转换业务对象]
style B fill:#f9f,stroke:#333
style C fill:#ccf,stroke:#333
设计模式解析:
- 模板方法模式:
- 封装固定流程:获取连接→准备语句→执行→处理结果→释放资源
- 开发者只需关注SQL和结果处理
- 回调机制:
- 通过
RowMapper实现结果集到对象的映射 - 使用
PreparedStatementCreator定制语句创建
- 通过
企业级查询优化:
// 分页查询最佳实践
public Page<User> findUsersByPage(int pageNum, int pageSize) {
String countSql = "SELECT COUNT(*) FROM users";
int total = jdbcTemplate.queryForObject(countSql, Integer.class);
String dataSql = "SELECT * FROM users LIMIT ? OFFSET ?";
List<User> content = jdbcTemplate.query(
dataSql,
new Object[]{pageSize, (pageNum-1)*pageSize},
new BeanPropertyRowMapper<>(User.class)
);
return new Page<>(content, pageNum, pageSize, total);
}
// 查询结果缓存方案
@Cacheable(value = "users", key = "#name")
public User findByName(String name) {
return jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE name = ?",
new Object[]{name},
new BeanPropertyRowMapper<>(User.class)
);
}
2.2 事务管理引擎(原理级解析)
事务传播机制本质
// 传播机制伪代码实现
public void executeWithTransaction(TransactionDefinition definition) {
TransactionStatus status = null;
try {
// 判断当前是否存在事务
boolean existingTransaction = isExistingTransaction();
// 根据传播行为决定事务边界
if (definition.getPropagationBehavior() == PROPAGATION_REQUIRED) {
if (!existingTransaction) {
status = startNewTransaction(definition);
} else {
status = participateInExistingTransaction();
}
}
// 执行业务逻辑
businessLogic();
// 提交或回滚
if (status != null && !status.isCompleted()) {
commitTransaction(status);
}
} catch (Exception ex) {
handleRollback(status, ex);
throw ex;
}
}
隔离级别对比表:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 性能影响 |
|---|---|---|---|---|
| READ_UNCOMMITTED | ✓ | ✓ | ✓ | 低 |
| READ_COMMITTED | × | ✓ | ✓ | 中 |
| REPEATABLE_READ | × | × | ✓ | 较高 |
| SERIALIZABLE | × | × | × | 高 |
生产环境配置建议:
spring:
datasource:
hikari:
isolation-level: TRANSACTION_REPEATABLE_READ
jpa:
properties:
hibernate:
connection:
# 设置MySQL实际隔离级别
isolation_level: 4 # 对应REPEATABLE_READ
2.3 MyBatis整合方案(原理与优化)
执行过程剖析
sequenceDiagram
participant A as Mapper接口
participant B as SqlSession
participant C as Executor
participant D as StatementHandler
participant E as JDBC
A->>B: 调用接口方法
B->>C: 获取Executor
C->>D: 创建StatementHandler
D->>E: 预编译SQL
E->>D: 返回结果集
D->>C: 结果处理
C->>B: 返回处理结果
B->>A: 返回业务对象
二级缓存优化策略:
<!-- 启用二级缓存 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- Mapper级别配置 -->
<mapper namespace="com.example.UserMapper">
<cache eviction="LRU"
flushInterval="60000"
size="1024"
readOnly="true"/>
</mapper>
插件开发实战:
// SQL执行时间监控插件
@Intercepts({
@Signature(type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class,
method = "update",
args = {MappedStatement.class, Object.class})
})
public class PerformanceInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(PerformanceInterceptor.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
String sqlId = mappedStatement.getId();
long start = System.currentTimeMillis();
try {
return invocation.proceed();
} finally {
long cost = System.currentTimeMillis() - start;
logger.info("SQL [{}] 执行耗时: {}ms", sqlId, cost);
Metrics.counter("sql_query_count").increment();
Metrics.timer("sql_duration").record(cost, TimeUnit.MILLISECONDS);
}
}
}
扩展说明总结
-
JDBC Template设计哲学:
- 通过模板方法消除样板代码
- 分离资源管理与业务逻辑
- 适合需要精细控制SQL的场景
-
事务管理的本质:
- 通过AOP实现声明式事务
- 传播机制本质是事务上下文的传递策略
- 隔离级别需要与数据库实际级别对齐
-
MyBatis最佳实践:
- 动态SQL适合复杂查询场景
- 二级缓存适合读多写少的业务
- 插件机制可扩展监控能力
-
性能优化方向:
graph TD A[数据持久化优化] --> B[连接池配置] A --> C[批处理操作] A --> D[合理使用缓存] A --> E[索引优化] B --> F[最大连接数] B --> G[超时配置] C --> H[批量插入] C --> I[批量更新] D --> J[一级缓存] D --> K[二级缓存]
2.4 JPA规范实践(高效ORM解决方案)
2.4.1 JPA核心概念与实体映射
实体类映射规范:
@Entity
@Table(name = "orders", indexes = {
@Index(name = "idx_order_user", columnList = "user_id"),
@Index(name = "idx_order_status", columnList = "status")
})
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 50)
private String orderNumber;
@Enumerated(EnumType.STRING)
@Column(length = 20)
private OrderStatus status;
@CreationTimestamp
private LocalDateTime createTime;
@UpdateTimestamp
private LocalDateTime updateTime;
// 关联关系配置
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
// 省略getter/setter
}
Repository接口智能方法推导:
public interface OrderRepository extends JpaRepository<Order, Long> {
// 根据状态分页查询
Page<Order> findByStatus(OrderStatus status, Pageable pageable);
// 复杂条件查询
@Query("SELECT o FROM Order o WHERE " +
"o.createTime BETWEEN :start AND :end " +
"AND o.totalAmount > :minAmount")
List<Order> findRecentHighValueOrders(
@Param("start") LocalDateTime start,
@Param("end") LocalDateTime end,
@Param("minAmount") BigDecimal minAmount);
// 动态查询
interface OrderSpec {
static Specification<Order> hasStatus(OrderStatus status) {
return (root, query, cb) ->
cb.equal(root.get("status"), status);
}
static Specification<Order> createdAfter(LocalDateTime time) {
return (root, query, cb) ->
cb.greaterThan(root.get("createTime"), time);
}
}
List<Order> findAll(Specification<Order> spec, Sort sort);
}
2.4.2 关联关系映射实战(电商订单系统案例)
一对多关系配置:
@Entity
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id", nullable = false)
private Order order;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id", nullable = false)
private Product product;
@Column(nullable = false)
private Integer quantity;
// 省略其他字段
}
// 级联操作示例
Order order = new Order();
order.addItem(new OrderItem(product1, 2));
order.addItem(new OrderItem(product2, 1));
orderRepository.save(order); // 自动保存所有关联项
多对多关系配置:
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany
@JoinTable(name = "product_category",
joinColumns = @JoinColumn(name = "product_id"),
inverseJoinColumns = @JoinColumn(name = "category_id"))
private Set<Category> categories = new HashSet<>();
}
@Entity
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany(mappedBy = "categories")
private Set<Product> products = new HashSet<>();
}
2.4.3 N+1查询问题解决方案(性能优化关键)
问题复现与诊断:
// 危险查询方式
List<Order> orders = orderRepository.findAll();
orders.forEach(order -> {
System.out.println(order.getItems().size()); // 每次访问触发查询
});
优化方案一:@EntityGraph立即加载:
public interface OrderRepository extends JpaRepository<Order, Long> {
@EntityGraph(attributePaths = {"items", "items.product"})
@Query("SELECT o FROM Order o WHERE o.id = :id")
Optional<Order> findByIdWithDetails(@Param("id") Long id);
}
// 生成SQL:
SELECT o.*, i.*, p.*
FROM orders o
LEFT JOIN order_item i ON o.id = i.order_id
LEFT JOIN product p ON i.product_id = p.id
WHERE o.id = ?
优化方案二:批量抓取策略:
# application.properties
spring.jpa.properties.hibernate.default_batch_fetch_size=20
-- 优化后的查询:
SELECT * FROM order_item WHERE order_id IN (?, ?, ...) -- 一次查询20个订单项
优化方案三:JOIN FETCH查询:
@Query("SELECT o FROM Order o " +
"LEFT JOIN FETCH o.items i " +
"LEFT JOIN FETCH i.product " +
"WHERE o.createTime > :startDate")
List<Order> findRecentOrdersWithDetails(LocalDateTime startDate);
2.4.4 审计与版本控制(企业级数据管理)
自动审计字段配置:
@EntityListeners(AuditingEntityListener.class)
@Entity
public class Product {
// ...
@CreatedBy
private String createdBy;
@LastModifiedBy
private String modifiedBy;
@Version
private Long version;
}
// 配置审计信息获取
@Configuration
@EnableJpaAuditing
public class AuditConfig {
@Bean
public AuditorAware<String> auditorAware() {
return () -> Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.map(Authentication::getName);
}
}
乐观锁控制案例:
@Service
@RequiredArgsConstructor
public class InventoryService {
private final ProductRepository productRepository;
@Transactional
public void reduceStock(Long productId, int quantity) {
Product product = productRepository.findById(productId)
.orElseThrow(() -> new ProductNotFoundException(productId));
if (product.getStock() < quantity) {
throw new InsufficientStockException();
}
product.setStock(product.getStock() - quantity);
productRepository.save(product); // 自动检查@Version字段
}
}
// 异常处理:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(OptimisticLockingFailureException.class)
public ResponseEntity<?> handleOptimisticLocking() {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(Map.of("error", "数据版本冲突,请刷新后重试"));
}
}
2.4.5 复杂查询解决方案(动态条件组合)
Criteria API动态查询:
public class OrderSpecifications {
public static Specification<Order> buildSearchSpec(
String orderNumber,
LocalDate startDate,
LocalDate endDate,
BigDecimal minAmount) {
return (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.hasText(orderNumber)) {
predicates.add(cb.like(root.get("orderNumber"), "%" + orderNumber + "%"));
}
if (startDate != null) {
predicates.add(cb.greaterThanOrEqualTo(
root.get("createTime"), startDate.atStartOfDay()));
}
if (endDate != null) {
predicates.add(cb.lessThanOrEqualTo(
root.get("createTime"), endDate.plusDays(1).atStartOfDay()));
}
if (minAmount != null) {
predicates.add(cb.greaterThanOrEqualTo(
root.get("totalAmount"), minAmount));
}
return cb.and(predicates.toArray(new Predicate[0]));
};
}
}
// 业务层使用
public Page<Order> searchOrders(OrderSearchCriteria criteria, Pageable pageable) {
Specification<Order> spec = OrderSpecifications.buildSearchSpec(
criteria.getOrderNumber(),
criteria.getStartDate(),
criteria.getEndDate(),
criteria.getMinAmount()
);
return orderRepository.findAll(spec, pageable);
}
QueryDSL集成方案:
<!-- Maven依赖 -->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>5.0.0</version>
</dependency>
// 自动生成Q类
@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QOrder extends EntityPathBase<Order> {
// 自动生成查询元模型
}
// 动态查询实现
public List<Order> findOrders(QOrderQuery query) {
QOrder order = QOrder.order;
JPAQuery<Order> jpaQuery = new JPAQuery<>(entityManager);
return jpaQuery.select(order)
.from(order)
.where(order.status.eq(query.getStatus())
.and(order.totalAmount.goe(query.getMinAmount()))
.and(order.createTime.between(query.getStart(), query.getEnd())))
.orderBy(order.createTime.desc())
.fetch();
}
扩展说明总结
-
JPA核心价值:
- 通过对象映射简化数据库操作
- 提供标准化的持久层接口
- 支持面向对象的查询语言(JPQL)
-
关联关系设计原则:
- 优先使用
LAZY加载避免不必要查询 - 明确维护方(mappedBy)
- 谨慎使用级联操作
- 优先使用
-
性能优化重点:
graph TD A[JPA性能优化] --> B[避免N+1查询] A --> C[合理使用二级缓存] A --> D[批量操作优化] B --> E["@EntityGraph"] B --> F[Batch Fetch] C --> G[Ehcache集成] D --> H[批量插入] D --> I[批量更新] -
复杂查询选择策略:
- 简单查询:使用方法推导
- 中等复杂度:使用
@Query注解 - 动态条件:使用Specification或QueryDSL 以下针对关键技术的深度扩展说明:
2.4.6 QueryDSL深度集成(企业级动态查询方案)
完整集成流程
1. Maven配置(含APT插件):
<dependencies>
<!-- QueryDSL核心依赖 -->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>5.0.0</version>
</dependency>
<!-- 代码生成插件 -->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- APT处理器配置 -->
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/querydsl</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
2. 自动生成的Q类示例:
// QOrder.java(自动生成)
@Generated("com.querydsl.codegen.EntitySerializer")
public class QOrder extends EntityPathBase<Order> {
private static final PathInits INITS = PathInits.DIRECT2;
public static final QOrder order = new QOrder("order");
public final NumberPath<Long> id = createNumber("id", Long.class);
public final StringPath orderNumber = createString("orderNumber");
public final ListPath<OrderItem, QOrderItem> items =
this.<OrderItem, QOrderItem>createList("items", OrderItem.class, QOrderItem.class, PathInits.DIRECT2);
public QOrder(String variable) {
super(Order.class, forVariable(variable));
}
}
3. 复杂查询构建示例:
@Repository
public class OrderCustomRepositoryImpl implements OrderCustomRepository {
@PersistenceContext
private EntityManager em;
@Override
public Page<Order> searchOrders(OrderSearchCondition condition, Pageable pageable) {
QOrder order = QOrder.order;
QOrderItem item = QOrderItem.orderItem;
JPAQuery<Order> query = new JPAQueryFactory(em)
.selectFrom(order)
.leftJoin(order.items, item).fetchJoin()
.where(
order.status.eq(condition.getStatus())
.and(order.createTime.between(
condition.getStartDate().atStartOfDay(),
condition.getEndDate().plusDays(1).atStartOfDay()
))
.and(item.product.price.gt(condition.getMinPrice()))
)
.orderBy(order.createTime.desc())
.groupBy(order.id);
// 分页处理
long total = query.fetchCount();
List<Order> content = query
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
return new PageImpl<>(content, pageable, total);
}
}
4. 动态排序支持:
private OrderSpecifier<?>[] createOrderSpecifiers(Pageable pageable) {
return pageable.getSort().stream()
.map(order -> {
PathBuilder<Order> path = new PathBuilder<>(Order.class, "order");
return new OrderSpecifier(
order.isAscending() ? Order.ASC : Order.DESC,
path.get(order.getProperty())
);
})
.toArray(OrderSpecifier[]::new);
}
2.4.7 二级缓存配置(生产级优化方案)
Ehcache3集成全流程
1. 依赖配置:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jcache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.8</version>
</dependency>
2. ehcache.xml配置:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd">
<persistence directory="/data/cache"/>
<cache alias="productCache">
<key-type>java.lang.Long</key-type>
<value-type>com.example.Product</value-type>
<expiry>
<ttl unit="minutes">30</ttl>
</expiry>
<resources>
<heap unit="MB">100</heap>
<offheap unit="MB">200</offheap>
<disk persistent="true" unit="GB">1</disk>
</resources>
</cache>
</config>
3. 实体类缓存注解:
@Entity
@Cacheable
@org.hibernate.annotations.Cache(
usage = CacheConcurrencyStrategy.READ_WRITE,
region = "productCache"
)
public class Product {
// ...
}
4. Spring Boot配置:
# application.properties
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.region.factory_class=jcache
spring.jpa.properties.hibernate.javax.cache.provider=org.ehcache.jsr107.EhcacheCachingProvider
spring.jpa.properties.hibernate.javax.cache.uri=classpath:ehcache.xml
5. 缓存监控方案:
@Bean
public MeterRegistryCustomizer<MeterRegistry> cacheMetrics(CachingProvider provider) {
return registry -> {
CacheManager cacheManager = provider.getCacheManager();
cacheManager.getCacheNames().forEach(name -> {
Cache<?, ?> cache = cacheManager.getCache(name);
registry.gauge("cache.size", Tags.of("name", name), cache::size);
});
};
}
2.4.8 乐观锁与审计增强实现
乐观锁深度控制
// 实体类版本控制
@Entity
public class Inventory {
@Id
private Long productId;
@Version
private Integer version;
private Integer stock;
}
// 重试策略实现
@Retryable(value = OptimisticLockingFailureException.class,
maxAttempts = 3,
backoff = @Backoff(delay = 100))
public void updateStockWithRetry(Long productId, int delta) {
Inventory inv = inventoryRepo.findById(productId)
.orElseThrow();
inv.setStock(inv.getStock() + delta);
inventoryRepo.save(inv);
}
审计功能扩展
// 自定义审计字段
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {
@CreatedDate
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime modifiedDate;
@CreatedBy
private String createdBy;
@LastModifiedBy
private String modifiedBy;
}
// 多租户审计实现
@Bean
public AuditorAware<TenantUser> auditorProvider() {
return () -> Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.filter(authentication -> authentication.getPrincipal() instanceof TenantUser)
.map(authentication -> (TenantUser) authentication.getPrincipal());
}
2.4.9 复杂类型处理(JSON/XML字段映射)
JSON类型处理(Hibernate6+):
@Entity
public class ProductSpec {
@Id
private Long id;
@JdbcTypeCode(SqlTypes.JSON)
@Column(columnDefinition = "jsonb")
private Map<String, Object> attributes = new HashMap<>();
}
// 自定义JSON转换器
@Converter(autoApply = true)
public class JsonConverter implements AttributeConverter<Map<String, Object>, String> {
private static final ObjectMapper mapper = new ObjectMapper();
@Override
public String convertToDatabaseColumn(Map<String, Object> attribute) {
try {
return mapper.writeValueAsString(attribute);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("JSON转换失败", e);
}
}
@Override
public Map<String, Object> convertToEntityAttribute(String dbData) {
try {
return mapper.readValue(dbData, new TypeReference<>() {});
} catch (IOException e) {
throw new IllegalArgumentException("JSON解析失败", e);
}
}
}
扩展技术总结
-
QueryDSL最佳实践:
graph LR A[动态查询需求] --> B{简单条件} B -->|是| C[方法命名推导] B -->|否| D{中等复杂度} D -->|是| E["@Query注解"] D -->|否| F{高度动态} F -->|是| G[QueryDSL] F -->|否| H[Criteria API] -
缓存策略选择:
策略类型 适用场景 注意事项 READ_ONLY 只读数据(字典表等) 不支持更新操作 NONSTRICT_READ_WRITE 偶尔更新的数据 可能短暂数据不一致 READ_WRITE 高频读写数据 需要事务支持 TRANSACTIONAL 分布式事务环境 性能开销较大 -
乐观锁实现要点:
- 使用
@Version字段控制版本 - 结合重试机制处理并发冲突
- 前端需处理HTTP 409 Conflict响应
- 使用
-
复杂类型存储方案:
- JSON类型:适合非结构化数据
- XML类型:适合严格模式数据
- 二进制类型:适合文件存储
2.5 分布式事务方案(Saga模式深度实践)
2.5.1 分布式事务核心挑战
典型问题场景:
电商系统下单流程:
1. 订单服务 → 创建订单
2. 库存服务 → 扣减库存
3. 物流服务 → 生成物流单
异常场景:
- 订单创建成功但库存不足
- 库存扣减后物流服务不可用
- 网络分区导致部分服务成功
事务模式对比:
| 模式 | 一致性模型 | 实现复杂度 | 适用场景 |
|---|---|---|---|
| 2PC | 强一致性 | 高 | 数据库层跨库事务 |
| TCC | 最终一致性 | 高 | 高一致性要求的金融交易 |
| Saga | 最终一致性 | 中 | 长事务、跨服务操作 |
| 本地消息表 | 最终一致性 | 低 | 异步通知型业务 |
2.5.2 Saga模式实现原理
模式架构图
sequenceDiagram
participant C as 协调器
participant O as 订单服务
participant I as 库存服务
participant L as 物流服务
C->>O: 1. 创建订单
O-->>C: 订单创建成功
C->>I: 2. 扣减库存
I-->>C: 库存扣减成功
C->>L: 3. 创建物流单
L-->>C: 物流单创建失败
C->>I: 4. 补偿库存
I-->>C: 库存恢复成功
C->>O: 5. 取消订单
实现方式对比
| 类型 | 控制方式 | 优点 | 缺点 |
|---|---|---|---|
| 编排式(Choreography) | 事件驱动 | 去中心化、服务自治 | 调试困难、易现循环依赖 |
| 编排式(Orchestration) | 中央协调器 | 流程可视化、易管理 | 单点风险、耦合协调逻辑 |
2.5.3 订单-库存-物流Saga实现(编排式)
项目结构
saga-demo/
├── order-service/
├── inventory-service/
├── logistics-service/
└── saga-coordinator/
协调器核心实现
// Saga协调器配置
@Configuration
public class SagaConfig {
@Bean
public SagaCoordinator sagaCoordinator(
OrderService orderService,
InventoryService inventoryService,
LogisticsService logisticsService) {
return SagaBuilder
.begin("创建订单", orderService::createOrder)
.then("扣减库存", inventoryService::deductStock)
.then("生成物流单", logisticsService::createLogistics)
.withCompensation("订单取消", orderService::cancelOrder)
.withCompensation("库存恢复", inventoryService::restoreStock)
.build();
}
}
// Saga执行器
public class SagaExecutor {
private final List<SagaStep> steps;
private final List<BiConsumer<SagaContext, Exception>> compensations = new ArrayList<>();
public void execute(SagaContext context) {
try {
for (SagaStep step : steps) {
step.execute(context);
}
} catch (Exception e) {
executeCompensation(context);
throw new SagaException("Saga执行失败", e);
}
}
private void executeCompensation(SagaContext context) {
Collections.reverse(compensations);
compensations.forEach(comp -> comp.accept(context, null));
}
}
订单服务实现
@Service
public class OrderService {
private static final Map<Long, Order> orders = new ConcurrentHashMap<>();
@SagaParticipant
public void createOrder(SagaContext context) {
Order order = new Order(
context.get("userId"),
context.get("productId"),
context.get("quantity")
);
orders.put(order.getId(), order);
context.put("orderId", order.getId());
}
@Compensation
public void cancelOrder(SagaContext context) {
Long orderId = context.get("orderId");
orders.get(orderId).setStatus(OrderStatus.CANCELLED);
}
}
2.5.4 异常处理与恢复机制
重试策略配置:
@Bean
public RetryTemplate sagaRetryTemplate() {
return new RetryTemplateBuilder()
.maxAttempts(3)
.exponentialBackoff(1000, 2, 5000)
.retryOn(SagaRetryableException.class)
.build();
}
// 服务层应用
@SagaParticipant
@Retryable(retryFor = InventoryServiceException.class,
maxAttempts = 3,
backoff = @Backoff(delay = 1000))
public void deductStock(SagaContext context) {
// 库存扣减逻辑
if (currentStock < required) {
throw new InventoryServiceException("库存不足");
}
// ...
}
事务日志记录:
@Entity
public class SagaLog {
@Id
private String sagaId;
private SagaStatus status;
@Lob
private String contextJson;
@ElementCollection
private List<String> executedSteps;
@ElementCollection
private List<String> compensatedSteps;
}
// 日志切面
@Aspect
@Component
public class SagaLogAspect {
@Autowired
private SagaLogRepository logRepository;
@Around("@annotation(SagaParticipant)")
public Object logStep(ProceedingJoinPoint pjp) throws Throwable {
String stepName = ((MethodSignature)pjp.getSignature()).getMethod().getName();
SagaContext context = (SagaContext) pjp.getArgs()[0];
SagaLog log = logRepository.findBySagaId(context.getSagaId())
.orElseGet(() -> new SagaLog(context.getSagaId()));
try {
Object result = pjp.proceed();
log.addExecutedStep(stepName);
logRepository.save(log);
return result;
} catch (Exception e) {
log.addCompensatedStep(stepName);
log.setStatus(SagaStatus.FAILED);
logRepository.save(log);
throw e;
}
}
}
2.5.5 生产环境部署方案
Kubernetes部署配置:
# saga-coordinator-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: saga-coordinator
spec:
replicas: 3
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
spec:
containers:
- name: coordinator
image: registry.example.com/saga-coordinator:1.0.0
env:
- name: SPRING_DATASOURCE_URL
value: jdbc:mysql://mysql-cluster:3306/saga
- name: SPRING_REDIS_HOST
value: redis-sentinel
# 服务熔断配置
spring:
cloud:
circuitbreaker:
resilience4j:
instances:
saga:
failureRateThreshold: 50
waitDurationInOpenState: 10s
slidingWindowSize: 10
监控指标暴露:
@Bean
public MeterRegistryCustomizer<MeterRegistry> sagaMetrics() {
return registry -> {
Gauge.builder("saga.active_count",
SagaCoordinator::getActiveCount)
.register(registry);
Timer.builder("saga.duration")
.publishPercentiles(0.5, 0.95)
.register(registry);
};
}
总结与最佳实践
Saga模式适用场景:
graph TD
A[是否长周期事务?] -->|是| B[考虑Saga]
A -->|否| C[考虑本地事务]
B --> D{是否需要强一致性?}
D -->|是| E[结合TCC模式]
D -->|否| F[纯Saga实现]
实施要点:
- 服务自治:每个参与者服务需独立管理本地事务
- 幂等设计:所有操作必须支持重试
- 补偿事务:确保每个正向操作都有对应的补偿逻辑
- 可视化监控:记录完整事务链路
- 压力测试:验证分布式锁和重试机制的性能
容错模式推荐:
| 故障类型 | 处理策略 |
|---|---|
| 业务校验失败 | 立即中断并触发补偿 |
| 网络临时故障 | 指数退避重试 |
| 服务不可用 | 熔断降级+人工干预 |
| 数据不一致 | 定时对账修复 |