二、数据持久化篇(深度增强版)

ops/2025/2/13 5:29:06/

二、数据持久化篇(深度增强版)

2.1 JDBC Template深度解析

架构设计思想
DataSource
JdbcTemplate
执行SQL
处理结果集
转换业务对象

设计模式解析

  1. 模板方法模式

    • 封装固定流程:获取连接→准备语句→执行→处理结果→释放资源
    • 开发者只需关注SQL和结果处理
  2. 回调机制

    • 通过RowMapper实现结果集到对象的映射
    • 使用PreparedStatementCreator定制语句创建

企业级查询优化

java">// 分页查询最佳实践
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 事务管理引擎(原理级解析)

事务传播机制本质
java">// 传播机制伪代码实现
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_READjpa:properties:hibernate:connection:# 设置MySQL实际隔离级别isolation_level: 4  # 对应REPEATABLE_READ

2.3 MyBatis整合方案(原理与优化)

执行过程剖析
Mapper接口 SqlSession Executor StatementHandler JDBC 调用接口方法 获取Executor 创建StatementHandler 预编译SQL 返回结果集 结果处理 返回处理结果 返回业务对象 Mapper接口 SqlSession Executor StatementHandler JDBC

二级缓存优化策略

<!-- 启用二级缓存 -->
<settings><setting name="cacheEnabled" value="true"/>
</settings><!-- Mapper级别配置 -->
<mapper namespace="com.example.UserMapper"><cache eviction="LRU" flushInterval="60000"size="1024"readOnly="true"/>
</mapper>

插件开发实战

java">// 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);@Overridepublic 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);}}
}

扩展说明总结

  1. JDBC Template设计哲学

    • 通过模板方法消除样板代码
    • 分离资源管理与业务逻辑
    • 适合需要精细控制SQL的场景
  2. 事务管理的本质

    • 通过AOP实现声明式事务
    • 传播机制本质是事务上下文的传递策略
    • 隔离级别需要与数据库实际级别对齐
  3. MyBatis最佳实践

    • 动态SQL适合复杂查询场景
    • 二级缓存适合读多写少的业务
    • 插件机制可扩展监控能力
  4. 性能优化方向

    数据持久化优化
    连接池配置
    批处理操作
    合理使用缓存
    索引优化
    最大连接数
    超时配置
    批量插入
    批量更新
    一级缓存
    二级缓存

2.4 JPA规范实践(高效ORM解决方案)

2.4.1 JPA核心概念与实体映射

实体类映射规范

java">@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;@CreationTimestampprivate LocalDateTime createTime;@UpdateTimestampprivate LocalDateTime updateTime;// 关联关系配置@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)private List<OrderItem> items = new ArrayList<>();// 省略getter/setter
}

Repository接口智能方法推导

java">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 关联关系映射实战(电商订单系统案例)

一对多关系配置

java">@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); // 自动保存所有关联项

多对多关系配置

java">@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查询问题解决方案(性能优化关键)

问题复现与诊断

java">// 危险查询方式
List<Order> orders = orderRepository.findAll();
orders.forEach(order -> {System.out.println(order.getItems().size()); // 每次访问触发查询
});

优化方案一:@EntityGraph立即加载

java">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查询

java">@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 审计与版本控制(企业级数据管理)

自动审计字段配置

java">@EntityListeners(AuditingEntityListener.class)
@Entity
public class Product {// ...@CreatedByprivate String createdBy;@LastModifiedByprivate String modifiedBy;@Versionprivate Long version;
}// 配置审计信息获取
@Configuration
@EnableJpaAuditing
public class AuditConfig {@Beanpublic AuditorAware<String> auditorAware() {return () -> Optional.ofNullable(SecurityContextHolder.getContext()).map(SecurityContext::getAuthentication).map(Authentication::getName);}
}

乐观锁控制案例

java">@Service
@RequiredArgsConstructor
public class InventoryService {private final ProductRepository productRepository;@Transactionalpublic 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动态查询

java">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>
java">// 自动生成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();
}

扩展说明总结

  1. JPA核心价值

    • 通过对象映射简化数据库操作
    • 提供标准化的持久层接口
    • 支持面向对象的查询语言(JPQL)
  2. 关联关系设计原则

    • 优先使用LAZY加载避免不必要查询
    • 明确维护方(mappedBy)
    • 谨慎使用级联操作
  3. 性能优化重点

    JPA性能优化
    避免N+1查询
    合理使用二级缓存
    批量操作优化
    @EntityGraph
    Batch Fetch
    Ehcache集成
    批量插入
    批量更新
  4. 复杂查询选择策略

    • 简单查询:使用方法推导
    • 中等复杂度:使用@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类示例

java">// 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. 复杂查询构建示例

java">@Repository
public class OrderCustomRepositoryImpl implements OrderCustomRepository {@PersistenceContextprivate EntityManager em;@Overridepublic 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. 动态排序支持

java">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. 实体类缓存注解

java">@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. 缓存监控方案

java">@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 乐观锁与审计增强实现

乐观锁深度控制
java">// 实体类版本控制
@Entity
public class Inventory {@Idprivate Long productId;@Versionprivate 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);
}
审计功能扩展
java">// 自定义审计字段
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {@CreatedDateprivate LocalDateTime createdDate;@LastModifiedDateprivate LocalDateTime modifiedDate;@CreatedByprivate String createdBy;@LastModifiedByprivate 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+)

java">@Entity
public class ProductSpec {@Idprivate 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();@Overridepublic String convertToDatabaseColumn(Map<String, Object> attribute) {try {return mapper.writeValueAsString(attribute);} catch (JsonProcessingException e) {throw new IllegalArgumentException("JSON转换失败", e);}}@Overridepublic Map<String, Object> convertToEntityAttribute(String dbData) {try {return mapper.readValue(dbData, new TypeReference<>() {});} catch (IOException e) {throw new IllegalArgumentException("JSON解析失败", e);}}
}

扩展技术总结

  1. QueryDSL最佳实践

    动态查询需求
    简单条件
    方法命名推导
    中等复杂度
    @Query注解
    高度动态
    QueryDSL
    Criteria API
  2. 缓存策略选择

    策略类型适用场景注意事项
    READ_ONLY只读数据(字典表等)不支持更新操作
    NONSTRICT_READ_WRITE偶尔更新的数据可能短暂数据不一致
    READ_WRITE高频读写数据需要事务支持
    TRANSACTIONAL分布式事务环境性能开销较大
  3. 乐观锁实现要点

    • 使用@Version字段控制版本
    • 结合重试机制处理并发冲突
    • 前端需处理HTTP 409 Conflict响应
  4. 复杂类型存储方案

    • JSON类型:适合非结构化数据
    • XML类型:适合严格模式数据
    • 二进制类型:适合文件存储

2.5 分布式事务方案(Saga模式深度实践)

2.5.1 分布式事务核心挑战

典型问题场景

电商系统下单流程:
1. 订单服务 → 创建订单
2. 库存服务 → 扣减库存
3. 物流服务 → 生成物流单异常场景:
- 订单创建成功但库存不足
- 库存扣减后物流服务不可用
- 网络分区导致部分服务成功

事务模式对比

模式一致性模型实现复杂度适用场景
2PC强一致性数据库层跨库事务
TCC最终一致性高一致性要求的金融交易
Saga最终一致性长事务、跨服务操作
本地消息表最终一致性异步通知型业务

2.5.2 Saga模式实现原理

模式架构图
协调器 订单服务 库存服务 物流服务 1. 创建订单 订单创建成功 2. 扣减库存 库存扣减成功 3. 创建物流单 物流单创建失败 4. 补偿库存 库存恢复成功 5. 取消订单 协调器 订单服务 库存服务 物流服务
实现方式对比
类型控制方式优点缺点
编排式(Choreography)事件驱动去中心化、服务自治调试困难、易现循环依赖
编排式(Orchestration)中央协调器流程可视化、易管理单点风险、耦合协调逻辑

2.5.3 订单-库存-物流Saga实现(编排式)

项目结构
saga-demo/
├── order-service/
├── inventory-service/
├── logistics-service/
└── saga-coordinator/
协调器核心实现
java">// Saga协调器配置
@Configuration
public class SagaConfig {@Beanpublic 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));}
}
订单服务实现
java">@Service
public class OrderService {private static final Map<Long, Order> orders = new ConcurrentHashMap<>();@SagaParticipantpublic 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());}@Compensationpublic void cancelOrder(SagaContext context) {Long orderId = context.get("orderId");orders.get(orderId).setStatus(OrderStatus.CANCELLED);}
}

2.5.4 异常处理与恢复机制

重试策略配置

java">@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("库存不足");}// ...
}

事务日志记录

java">@Entity
public class SagaLog {@Idprivate String sagaId;private SagaStatus status;@Lobprivate String contextJson;@ElementCollectionprivate List<String> executedSteps;@ElementCollectionprivate List<String> compensatedSteps;
}// 日志切面
@Aspect
@Component
public class SagaLogAspect {@Autowiredprivate 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: 3strategy:rollingUpdate:maxSurge: 1maxUnavailable: 0template:spec:containers:- name: coordinatorimage: registry.example.com/saga-coordinator:1.0.0env:- name: SPRING_DATASOURCE_URLvalue: jdbc:mysql://mysql-cluster:3306/saga- name: SPRING_REDIS_HOSTvalue: redis-sentinel# 服务熔断配置
spring:cloud:circuitbreaker:resilience4j:instances:saga:failureRateThreshold: 50waitDurationInOpenState: 10sslidingWindowSize: 10

监控指标暴露

java">@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模式适用场景

是否长周期事务?
考虑Saga
考虑本地事务
是否需要强一致性?
结合TCC模式
纯Saga实现

实施要点

  1. 服务自治:每个参与者服务需独立管理本地事务
  2. 幂等设计:所有操作必须支持重试
  3. 补偿事务:确保每个正向操作都有对应的补偿逻辑
  4. 可视化监控:记录完整事务链路
  5. 压力测试:验证分布式锁和重试机制的性能

容错模式推荐

故障类型处理策略
业务校验失败立即中断并触发补偿
网络临时故障指数退避重试
服务不可用熔断降级+人工干预
数据不一致定时对账修复

http://www.ppmy.cn/ops/157968.html

相关文章

JEECGBOOT前端VUE3版本浏览器兼容支持chrome>=76版本方法

JEECGBOOT最新的前端VUE3版本使用的 VITE最新版本Ant design vue最新版本。 部署到生产环境以后发现&#xff0c;chrome76-100左右&#xff0c;CSS样式会乱掉失效&#xff0c;不太兼容&#xff0c;103以上的没问题。 尝试了三种方法&#xff0c;前两种都失败了&#xff0c;第三…

MVCC面试怎么答

说到mvcc这个比较抽象的概念&#xff0c;很多人都有点束手无策。因为它实际上偏理论&#xff0c;实际应用中很难用到。但在面试中出现频率又很高&#xff0c;一问大部分都G。所以怎么精简回答并且能抓住重点就很关键了。往上详细解说MVCC的太多了&#xff0c;我这里没那么多废话…

最新版Edge浏览器集成ActiveX控件之金山WpsDocFrame控件

背景 WpsDocFrame控件‌是由金山公司开发的ActiveX控件&#xff0c;主要用于OA系统中&#xff0c;支持在浏览器中嵌入WPS文档的查看和编辑功能。 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有…

问卷数据分析|SPSS实操之单因素方差分析

适用条件&#xff1a; 检验分类变量和定量变量之间的差异 分类变量数量要大于等于三 具体操作&#xff1a; 1.选择分析--比较平均值--单因素ANOVA检验 2. 下方填分类变量&#xff0c;上方为各个量表数据Z1-Y2 3. 点击选项&#xff0c;选择描述和方差齐性检验 4.此处为结果数…

Pandas数据填充(fill)中的那些坑:避免机器学习中的数据泄露

1. 问题背景 在处理时间序列数据时,经常会遇到缺失值需要填充。Pandas提供了ffill(forward fill)和bfill(backward fill)两种填充方式,但使用不当可能会导致数据泄露,特别是在进行机器学习预测时。 2. 填充方式解析 2.1 基本概念 ffill(forward fill): 用前面的值填充后面的…

objectArx2016使用python3.9.7配置实践

写在前面: 笔者有一些python代码, 需要结合到cad二次开发的项目中,并使用embed版本进行发布.记录一下配置过程,并加些分析,以备后期查用. ObjectArx配置Python 零 着重提醒一 Python安装版本和embed版本1.1 下载1.2 安装版本的设置1)安装参数设置2)安装版本Python内重要文件 1.…

机器学习中过拟合和欠拟合问题处理方法总结

目录 一、背景二、过拟合(Overfitting)2.1 基本概念2.2 过拟合4个最主要的特征2.3 防止过拟合的11个有效方法 三、欠拟合&#xff08;Underfitting&#xff09;3.1 基本概念3.2 欠拟合的4个特征3.3 防止欠拟合的11个有效方法 四、总结五、参考资料 一、背景 在机器学习模型训练…

【Elasticsearch】bucket_sort

Elasticsearch 的bucket_sort聚合是一种管道聚合&#xff0c;用于对父多桶聚合&#xff08;如terms、date_histogram、histogram等&#xff09;的桶进行排序。以下是关于bucket_sort的详细说明&#xff1a; 1.基本功能 bucket_sort聚合可以对父聚合返回的桶进行排序&#xff…