当前位置: 首页 > news >正文

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

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

2.1 JDBC Template深度解析

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

设计模式解析

  1. 模板方法模式

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

    • 通过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_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>

插件开发实战

// 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核心概念与实体映射

实体类映射规范

@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接口智能方法推导

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 {// ...@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);}
}

乐观锁控制案例

@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动态查询

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();
}

扩展说明总结

  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类示例

// 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 {@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. 动态排序支持

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 {@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);
}
审计功能扩展
// 自定义审计字段
@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+)

@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/
协调器核心实现
// 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));}
}
订单服务实现
@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 异常处理与恢复机制

重试策略配置

@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 {@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

监控指标暴露

@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. 压力测试:验证分布式锁和重试机制的性能

容错模式推荐

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

相关文章:

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

二、数据持久化篇&#xff08;深度增强版&#xff09; 2.1 JDBC Template深度解析 架构设计思想 #mermaid-svg-y2IrKiVu2gzenoCB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-y2IrKiVu2gzenoCB .error-icon{fil…...

时间敏感和非时间敏感流量的性能保证配置

论文标题 中文标题&#xff1a; 时间敏感和非时间敏感流量的性能保证配置 英文标题&#xff1a; Provisioning of Time-Sensitive and non-Time-Sensitive Flows with Assured Performance 作者信息 Luis Velasco, Gianluca Graziadei, Sima Barzegar, Marc Ruiz Optical Co…...

k8s管理工具之lens

什么是lens Lens 是当前市场上最强大的K8S IDE。它是一个独立的单机应用&#xff0c;可以同时运行在macOS、Windows和Linux上。 作为K8S IDE&#xff0c;该有的它基本都有了&#xff01; 集群管理 导入已有集群 首先&#xff0c;你需要在 Lens 中添加你的 Kubernetes 集群。点…...

kafka介绍,kafka集群环境搭建,kafka命令测试,C++实现kafka客户端

目录 kafka介绍kafka集群环境搭建zookeeper安装与配置kafka安装与配置 kafka命令测试C实现kafka客户端librdkafka库编译新版本cmake编译cppkafka库编译C实现kafka生产者和消费者客户端 kafka介绍 定义与概述 Apache Kafka 是一个开源的分布式流处理平台&#xff0c;最初由 Lin…...

DeepSeek的蒸馏技术:让模型推理更快

DeepSeek系列模型&#xff0c;如DeepSeek-R1-Distill-Qwen-7B&#xff0c;采用了知识蒸馏&#xff08;Knowledge Distillation&#xff09;技术&#xff0c;这是一种强大的模型压缩和优化方法。通过蒸馏&#xff0c;DeepSeek模型在保持甚至提升性能的同时&#xff0c;实现了更快…...

SAP-ABAP:dialog界面中的数据块Event Block详解举例

在SAP的Dialog程序开发中&#xff0c;Event Block&#xff08;事件块&#xff09;是屏幕流逻辑&#xff08;Flow Logic&#xff09;中的关键部分&#xff0c;用于定义屏幕在特定事件触发时执行的逻辑。Event Block通常与ABAP模块&#xff08;Module&#xff09;结合使用&#x…...

微信小程序 - 模版语法

声明和绑定数据 小程序页面中使用的数据均需要在 Page() 方法的 data 对象中进行声明定义 在将数据声明好以后&#xff0c;需要在 WXML 中绑定数据&#xff0c;数据绑定最简单的方式是使用 Mustache 语法&#xff08;双大括号&#xff09;将变量包起来。 在 {{ }} 内部可以做…...

mapbox进阶,添加绘图扩展插件,裁剪线

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…...

Dav_笔记14:优化程序提示 HINTs -2

优化方法和目标的提示 ALL_ROWS和FIRST_ROWS&#xff08;n&#xff09;提示允许您在优化方法和目标之间进行选择。如果SQL语句具有指定优化方法和目标的提示&#xff0c;则优化程序将使用指定的方法&#xff0c;无论是否存在统计信息&#xff0c;OPTIMIZER_MODE初始化参数的值…...

Oracle ORA-00054

ORA-00054: resource busy and acquire with NOWAlT specified or timeout expire 错误 ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired 是 Oracle 数据库中常见的一个错误&#xff0c;通常发生在尝试获取一个已经被其他会话占用的资源时。这…...

ABB能源自动化选用宏集Cogent DataHub避免DCOM问题,实现高效、安全的数据传输

案例概况 ABB能源自动化公司通过宏集Cogent DataHub软件将电厂设施的数据实时传输到公司办公室&#xff0c;实现了OPC隧道/镜像解决方案&#xff0c;在电厂和公司网络之间建立了一个安全、可靠的连接&#xff0c;确保数据传输的高度安全&#xff0c;减少入侵风险。 &#xff0…...

IP地址有哪些类型?

IP地址是计算机网络中用来识别和查找设备的唯一标识符。根据其作用和使用范围&#xff0c;IP地址可分为以下几种类型&#xff1a; 1.局域网IP地址 局域网IP地址又称内网IP地址&#xff0c;是局域网内用来识别和查找局域网设备的地址。局域网是一个相对较小的网络&#xff0c;…...

网络安全评估:保障设备与系统安全的关键

保障网络安全离不开对入网设备的安全评估&#xff0c;这种评估运用了多种技术和手段&#xff0c;对网络中的设备与系统进行详尽的检查。它能迅速发现并排除潜在的安全风险&#xff0c;对网络系统的安全稳定运行具有极其关键的作用。 测评目的 确保网络系统的安全与稳定是网络…...

一竞技瓦拉几亚S4预选:YB 2-0击败GG

在2月11号进行的PGL瓦拉几亚S4西欧区预选赛上,留在欧洲训练的YB战队以2-0击败GG战队晋级下一轮。双方对阵第二局:对线期YB就打出了优势,中期依靠卡尔带队进攻不断扩大经济优势,最终轻松碾压拿下比赛胜利,以下是对决战报。 YB战队在天辉。阵容是潮汐、卡尔、沙王、隐刺、发条。G…...

管式超滤膜分离技术在茶澄清浓缩领域的创新应用

管式超滤膜分离技术在茶澄清浓缩领域展现出广阔的前景&#xff0c;其独特优势和应用效果正逐渐改变着茶饮料行业的生产方式。以下是几个关键点&#xff0c;说明了这一技术为何具有如此积极的发展潜力&#xff1a; 1. 高效澄清与保留风味 管式超滤膜具有高精度的过滤能力&#x…...

maven web项目如何定义filter

在 Maven Web 项目中定义一个 Servlet 过滤器&#xff08;Filter&#xff09;&#xff0c;需要遵循 Java Servlet 规范&#xff0c;并利用 Maven 来管理项目结构和依赖。下面是如何在 Maven Web 项目中定义和配置一个过滤器的基本步骤&#xff1a; 1. 创建过滤器类 首先&…...

如何在MacOS上查看edge/chrome的扩展源码

步骤 进入管理扩展页面点击详细信息复制对应id在命令行键入 open ~/Library/Application Support/Microsoft Edge/Default/Extensions/${你刚刚复制的id} 即可打开访达中对应的更目录 注意 由于原生命令行无法直接处理空格 ,所以需要加转义符\,即&#xff1a;open ~/Librar…...

【学术投稿-2025年计算机视觉研究进展与应用国际学术会议 (ACVRA 2025)】CSS样式解析:行内、内部与外部样式的区别与优先级分析

简介 2025年计算机视觉研究进展与应用&#xff08;ACVRA 2025&#xff09;将于2025年2月28-3月2日在中国广州召开&#xff0c;会议将汇聚世界各地的顶尖学者、研究人员和行业专家&#xff0c;聚焦计算机视觉领域的最新研究动态与应用成就。本次会议将探讨前沿技术&#xff0c;…...

redis记录用户在线状态+活跃度

1.记录用户在线状态 redis的Bitmap记录用户在线状态 使用一个大的Bitmap,每个bit位对应一个用户IDbit值1表示在线,0表示离线用户ID与bit位的映射关系: bit位置 用户ID % bitmap容量 具体实现: # 用户上线时,设置对应bit为1 SETBIT online_users {user_id} 1# 用户下线时,设…...

vmware安装win7

1、版本说明 vmware workstation 16 win7 X64 2、安装步骤 安装步骤有点独特&#xff0c;先配置虚拟机&#xff0c;然后再虚拟机的虚拟光驱里添加下载的win7。 配置完了之后&#xff0c;点击要运行的虚拟机&#xff0c;然后一直往下走就可以完成系统的安装。 3、配置系统以解…...

OpenAI推出的Computer Use智能体:Operator是什么

OpenAI推出的Computer Use智能体:Operator是什么 是一款能像人一样与图形用户界面交互来操作计算机的AI智能体。以下是其核心原理及举例说明: 核心原理 感知: 屏幕截图获取:利用高性能屏幕捕获模块,如基于WebRTC的截图技术,以极低延迟获取高清晰度页面图像,为后续分析…...

[FastAdmin] 上传图片并加水印,压缩图片

1.app\common\library\Upload.php 文件 upload方法 /*** 普通上传* return \app\common\model\attachment|\think\Model* throws UploadException*/public function upload($savekey null){if (empty($this->file)) {throw new UploadException(__(No file upload or serv…...

二、k8s项目的生命周期

项目的生命周期 创建-----------》发布-----------》更新--------》回滚----------》删除 kubectl create deployment nginx1 --imagenginx:1.22 --replicas3 基于deployment控制器创建pod 控制器的名称是nginx1 pod使用的镜像:nginx:1.22 --replicas3 pod的数量有多少 3个…...

MySQL数据库入门到大蛇尚硅谷宋红康老师笔记 基础篇 part 10

第10章_创建和管理表 DDL&#xff1a;数据定义语言。CREATE \ALTER\ DROP \RENAME TRUNCATE DML&#xff1a;数据操作语言。INSERT \DELETE \UPDATE \SELECT&#xff08;重中之重&#xff09; DCL&#xff1a;数据控制语言。COMMIT \…...

python自动化测试之Pytest框架之YAML详解以及Parametrize数据驱动!

一、YAML详解 YAML是一种数据类型&#xff0c;它能够和JSON数据相互转化&#xff0c;它本身也是有很多数据类型可以满足我们接口 的参数类型&#xff0c;扩展名可以是.yml或.yaml 作用&#xff1a; 1.全局配置文件 基础路径&#xff0c;数据库信息&#xff0c;账号信息&…...

deepseek的CoT优势、两阶段训练的有效性学习笔记

文章目录 1 DeepSeek的CoT思维链的优势1.2 open-r1的CoT训练数据1.3 ReAct任务与CoT任务适用场景 2 AI推理方向&#xff1a;deepseek与deepmind的两条路线的差异2.1 PRM与ORM的两大学派分支的差异2.2 DeepSeek-R1的两阶段训练概述 1 DeepSeek的CoT思维链的优势 DeepSeek跟之前…...

计算机网络-MPLS转发原理

在上一篇关于 MPLS 基础的文章中&#xff0c;我们了解了 MPLS 的基本概念、术语以及它在网络中的重要性。今天&#xff0c;我们将深入探讨 MPLS 转发的原理与流程&#xff0c;帮助大家更好地理解 MPLS 是如何在实际网络中工作的。 一、MPLS 转发概述 MPLS 转发的本质是将数据…...

本地部署DeepSeek R1并搭建Web UI实现可视化交互的笔记

经过多天的挣扎和卸载了一些软件&#xff0c;终于下定决心在本地部署DeepSeek R1模型。部署和搭建过程非常简单和方便。 一、下载Ollama 进入Ollama官方网站(https://ollama.com),进入下载下载Ollama页面&#xff08;https://ollama.com/download&#xff09; 根据电脑的操作…...

港中文腾讯提出可穿戴3D资产生成方法BAG,可自动生成服装和配饰等3D资产如,并适应特定的人体模型。

今天给大家介绍一种名为BAG&#xff08;Body-Aligned 3D Wearable Asset Generation&#xff09;的新方法&#xff0c;可以自动生成可穿戴的3D资产&#xff0c;如服装和配饰&#xff0c;以适应特定的人体模型。BAG方法通过构建一个多视图图像扩散模型&#xff0c;生成与人体对齐…...

JUC并发—1.Java集合包底层源码剖析

大纲 1.为什么要对JDK源码剖析 2.ArrayList源码一&#xff1a;基本原理以及优缺点 3.ArrayList源码二&#xff1a;核心方法的原理 4.ArrayList源码三&#xff1a;数组扩容以及元素拷贝 5.LinkedList源码一&#xff1a;优缺点和使用场景 6.LinkedList源码二&#xff1a;双…...

使用Java爬虫获取京东商品评论API接口(JD.item_review)数据

一、引言 在电商领域&#xff0c;商品评论是用户决策的重要参考依据&#xff0c;也是商家优化产品和服务的重要数据来源。京东作为国内领先的电商平台&#xff0c;提供了丰富的API接口供开发者使用&#xff0c;其中JD.item_review接口可以获取商品的评论数据。通过这些数据&am…...

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

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

【自然语言处理】TextRank 算法提取关键词、短语、句(Python源码实现)

文章目录 一、TextRank 算法提取关键词 [工具包]二、TextRank 算法提取关键短语[工具包]三、TextRank 算法提取关键句[工具包]四、TextRank 算法提取关键句&#xff08;Python源码实现&#xff09; 一、TextRank 算法提取关键词 [工具包] 见链接 【自然语言处理】TextRank 算法…...

Git的常用命令及常见问题处理方法

目录 一、介绍二、常用 Git 命令1. 配置用户信息2. 初始化仓库3. 克隆远程仓库4. 查看状态5. 添加文件到暂存区6. 提交更改7. 查看提交历史8. 查看文件差异9. 查看分支10. 切换分支11. 合并分支12. 处理冲突13. 远程操作14. 标签管理15. 撤销操作 三、常见问题处理方法1. 无法推…...

第6章 6.1 ASP.NET Core MVC 项目

6.1.1 ASP.NET Core MVC 项目的搭建 进入VS环境&#xff0c;创建新的项目&#xff0c;选择【ASP.Net Core Web 应用&#xff08;模型-视图-控制器&#xff09;】如下图所示 编写项目名称 点击创建&#xff0c;进入项目后结构如下所示 wwwroot 文件夹为图片、JS、CSS等静态文件…...

ios通过xib创建控件

之前写过ios动态创建控件及添加事件&#xff0c;纯手工代码写控件&#xff0c;虽然比较灵活&#xff0c;但是就是代码量比较多。这次我们通过xib来创建app下载列表项 AppView.xib。一个imageview,一个label,一个button构成 1.创建AppView.xib 2.再创建xib对应的mode&#xff0…...

缓存组件<keep-alive>

缓存组件<keep-alive> 1.组件作用 组件, 默认会缓存内部的所有组件实例&#xff0c;当组件需要缓存时首先考虑使用此组件。 2.使用场景 场景1&#xff1a;tab切换时&#xff0c;对应的组件保持原状态&#xff0c;使用keep-alive组件 使用&#xff1a;KeepAlive | Vu…...

SAP ABAP调用DeepSeek API大模型接口

搜索了一下DeepSeek&#xff0c;发现有人已经实现了SAP的对接&#xff0c; 不登录网页&#xff0c;SAP如何使用DeepSeek快速编程&#xff0c;ABAP起飞啦~ 按照对应的注册流程和方法。总算做出了第一个能够直连DeepSeek的API abap程序。 效果不错。 report ZTOOL_ABAP_CALL_D…...

大数据与大模型:数字时代的共生力量

引言&#xff1a;大数据与大模型的崭新时代 在数字化浪潮汹涌澎湃的当下&#xff0c;大数据与大模型无疑是最为耀眼的两颗明星 &#xff0c;深刻地改变着我们的生活、工作和思维方式。大数据&#xff0c;作为信息时代的宝藏&#xff0c;蕴含着无尽的价值。从电商平台的海量交易…...

服务器使用宝塔面板Docker应用快速部署 DeepSeek-R1模型,实现Open WebUI访问使用

Deepseek这段时间非常火&#xff0c;最新推理模型Deepseek R1&#xff0c;都想装上试一试&#xff0c;特别是部署到服务器教程网上一堆教程好像没几个部署成功靠谱的&#xff0c;先说服务器上下载Ollama就难倒一堆人&#xff0c;每次都超时。今天终于在宝塔看到一篇 应用安装文…...

Qt - 地图相关 —— 3、Qt调用高德在线地图功能示例(附源码)

效果 作者其他相关文章链接:           Qt - 地图相关 —— 1、加载百度在线地图(附源码)           Qt - 地图相关 —— 2、Qt调用百度在线地图功能示例全集,包含线路规划、地铁线路查询等(附源码)           Qt - 地图相关 —— 3、Qt调用…...

Idea集成deepseek生成代码

今天我带大家在idea上安装CodeGpt插件&#xff0c;这个插件可以根据我们的提示词生产代码&#xff0c;我们一起试试。 1、安装插件 打开idea&#xff0c;再点击setting菜单&#xff0c;按以下步骤操作。 安装完成后&#xff0c;一定要点击第四步“ok”。再次点击菜单setting…...

HTTP 请求方式`application/x-www-form-urlencoded` 与 `application/json` 怎么用?有什么区别?

HTTP 请求方式总结&#xff1a;application/x-www-form-urlencoded 与 application/json 在前后端交互中&#xff0c;客户端发送数据到服务器的常见方式有两种&#xff1a;application/x-www-form-urlencoded 和 application/json。本文将详细介绍这两种请求方式的特点、使用方…...

开发指南099-同时传递文件和参数

平台后台接口一般情况下要求传递一个json对象&#xff08;对应后台需要一个继承RequestInfo的dto类&#xff09;&#xff0c;某些情况下需要同时传递文件和参数&#xff0c;该如何处理呢&#xff1f; 1、前端 const formData new FormData(); formData.append(file, this.f…...

【Pycharm+Git+Gitlab】安装部署(粗糙版)

1、安装Git 2、安装Pycharm&#xff08;这里选择的是社区版&#xff09; 3、桌面右键打开Git Bash 1&#xff09;设置全局用户名&#xff08;准备连接的Gitlab仓库的访问用户名&#xff09; git config ---global user.name "username"2&#xff09;设置全局邮箱&…...

k8s中部署nginx的pod

在当今数字化的浪潮中&#xff0c;容器编排技术成为了构建和管理应用程序的核心力量。Kubernetes&#xff08;简称 k8s&#xff09;作为容器编排领域的佼佼者&#xff0c;凭借其强大的自动化部署、扩展和管理能力&#xff0c;深受开发者和运维人员的青睐。而 Nginx 作为一款高性…...

kafka生产者之发送模式与ACK

文章目录 Kafka的发送模式Kafka的ack机制发送模式与ack的关联重试次数总结 在Kafka中&#xff0c;发送模式与ack机制紧密相关&#xff0c;它们共同影响着消息发送的可靠性和性能。 Kafka的发送模式 发后即忘&#xff08;Fire and Forget&#xff09;&#xff1a;生产者发送消息…...

Clion使用jlink进行程序下载

1. 打开首选项(Preference)的Build, Execution, Deployment里的Toolchains&#xff0c;新建MinGW分别选择arm-none-eabi-gcc、arm-none-eabi-g、arm-none-eabi-gdb选择对应的可执行文件。 具体可以参考进行前期配置https://blog.csdn.net/iyt2017/article/details/132411792 2…...

Go 1.4操作符指针理解

对于初学者来说操作符指针类型、指针、取地址容易混淆&#xff0c;多练就好了。 只需要记住两个符号&#xff1a;&&#xff08;取内存地址&#xff09;和*&#xff08;解引用&#xff09;。 定义和使用&#xff1a;你可以使用 & 操作符获取一个变量的内存地址&#x…...

MATLAB 生成脉冲序列 pulstran函数使用详解

MATLAB 生成脉冲序列 pulstran函数使用详解 目录 前言 一、参数说明 二、示例一 三、示例二 总结 前言 MATLAB中的pulstran函数用于生成脉冲序列&#xff0c;支持连续或离散脉冲。该函数通过将原型脉冲延迟并相加&#xff0c;生成脉冲序列&#xff0c;适用于信号处理和系统…...