二、数据持久化篇(深度增强版)
二、数据持久化篇(深度增强版)
2.1 JDBC Template深度解析
架构设计思想
设计模式解析:
-
模板方法模式:
- 封装固定流程:获取连接→准备语句→执行→处理结果→释放资源
- 开发者只需关注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_READjpa:properties:hibernate:connection:# 设置MySQL实际隔离级别isolation_level: 4 # 对应REPEATABLE_READ
2.3 MyBatis整合方案(原理与优化)
执行过程剖析
二级缓存优化策略:
<!-- 启用二级缓存 -->
<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);}}
}
扩展说明总结
-
JDBC Template设计哲学:
- 通过模板方法消除样板代码
- 分离资源管理与业务逻辑
- 适合需要精细控制SQL的场景
-
事务管理的本质:
- 通过AOP实现声明式事务
- 传播机制本质是事务上下文的传递策略
- 隔离级别需要与数据库实际级别对齐
-
MyBatis最佳实践:
- 动态SQL适合复杂查询场景
- 二级缓存适合读多写少的业务
- 插件机制可扩展监控能力
-
性能优化方向:
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();
}
扩展说明总结
-
JPA核心价值:
- 通过对象映射简化数据库操作
- 提供标准化的持久层接口
- 支持面向对象的查询语言(JPQL)
-
关联关系设计原则:
- 优先使用
LAZY
加载避免不必要查询 - 明确维护方(mappedBy)
- 谨慎使用级联操作
- 优先使用
-
性能优化重点:
-
复杂查询选择策略:
- 简单查询:使用方法推导
- 中等复杂度:使用
@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);}}
}
扩展技术总结
-
QueryDSL最佳实践:
-
缓存策略选择:
策略类型 适用场景 注意事项 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模式实现原理
模式架构图
实现方式对比
类型 | 控制方式 | 优点 | 缺点 |
---|---|---|---|
编排式(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模式适用场景:
实施要点:
- 服务自治:每个参与者服务需独立管理本地事务
- 幂等设计:所有操作必须支持重试
- 补偿事务:确保每个正向操作都有对应的补偿逻辑
- 可视化监控:记录完整事务链路
- 压力测试:验证分布式锁和重试机制的性能
容错模式推荐:
故障类型 | 处理策略 |
---|---|
业务校验失败 | 立即中断并触发补偿 |
网络临时故障 | 指数退避重试 |
服务不可用 | 熔断降级+人工干预 |
数据不一致 | 定时对账修复 |
相关文章:
二、数据持久化篇(深度增强版)
二、数据持久化篇(深度增强版) 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…...
时间敏感和非时间敏感流量的性能保证配置
论文标题 中文标题: 时间敏感和非时间敏感流量的性能保证配置 英文标题: 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。它是一个独立的单机应用,可以同时运行在macOS、Windows和Linux上。 作为K8S IDE,该有的它基本都有了! 集群管理 导入已有集群 首先,你需要在 Lens 中添加你的 Kubernetes 集群。点…...
kafka介绍,kafka集群环境搭建,kafka命令测试,C++实现kafka客户端
目录 kafka介绍kafka集群环境搭建zookeeper安装与配置kafka安装与配置 kafka命令测试C实现kafka客户端librdkafka库编译新版本cmake编译cppkafka库编译C实现kafka生产者和消费者客户端 kafka介绍 定义与概述 Apache Kafka 是一个开源的分布式流处理平台,最初由 Lin…...
DeepSeek的蒸馏技术:让模型推理更快
DeepSeek系列模型,如DeepSeek-R1-Distill-Qwen-7B,采用了知识蒸馏(Knowledge Distillation)技术,这是一种强大的模型压缩和优化方法。通过蒸馏,DeepSeek模型在保持甚至提升性能的同时,实现了更快…...
SAP-ABAP:dialog界面中的数据块Event Block详解举例
在SAP的Dialog程序开发中,Event Block(事件块)是屏幕流逻辑(Flow Logic)中的关键部分,用于定义屏幕在特定事件触发时执行的逻辑。Event Block通常与ABAP模块(Module)结合使用&#x…...
微信小程序 - 模版语法
声明和绑定数据 小程序页面中使用的数据均需要在 Page() 方法的 data 对象中进行声明定义 在将数据声明好以后,需要在 WXML 中绑定数据,数据绑定最简单的方式是使用 Mustache 语法(双大括号)将变量包起来。 在 {{ }} 内部可以做…...
mapbox进阶,添加绘图扩展插件,裁剪线
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…...
Dav_笔记14:优化程序提示 HINTs -2
优化方法和目标的提示 ALL_ROWS和FIRST_ROWS(n)提示允许您在优化方法和目标之间进行选择。如果SQL语句具有指定优化方法和目标的提示,则优化程序将使用指定的方法,无论是否存在统计信息,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 数据库中常见的一个错误,通常发生在尝试获取一个已经被其他会话占用的资源时。这…...
ABB能源自动化选用宏集Cogent DataHub避免DCOM问题,实现高效、安全的数据传输
案例概况 ABB能源自动化公司通过宏集Cogent DataHub软件将电厂设施的数据实时传输到公司办公室,实现了OPC隧道/镜像解决方案,在电厂和公司网络之间建立了一个安全、可靠的连接,确保数据传输的高度安全,减少入侵风险。 ࿰…...
IP地址有哪些类型?
IP地址是计算机网络中用来识别和查找设备的唯一标识符。根据其作用和使用范围,IP地址可分为以下几种类型: 1.局域网IP地址 局域网IP地址又称内网IP地址,是局域网内用来识别和查找局域网设备的地址。局域网是一个相对较小的网络,…...
网络安全评估:保障设备与系统安全的关键
保障网络安全离不开对入网设备的安全评估,这种评估运用了多种技术和手段,对网络中的设备与系统进行详尽的检查。它能迅速发现并排除潜在的安全风险,对网络系统的安全稳定运行具有极其关键的作用。 测评目的 确保网络系统的安全与稳定是网络…...
一竞技瓦拉几亚S4预选:YB 2-0击败GG
在2月11号进行的PGL瓦拉几亚S4西欧区预选赛上,留在欧洲训练的YB战队以2-0击败GG战队晋级下一轮。双方对阵第二局:对线期YB就打出了优势,中期依靠卡尔带队进攻不断扩大经济优势,最终轻松碾压拿下比赛胜利,以下是对决战报。 YB战队在天辉。阵容是潮汐、卡尔、沙王、隐刺、发条。G…...
管式超滤膜分离技术在茶澄清浓缩领域的创新应用
管式超滤膜分离技术在茶澄清浓缩领域展现出广阔的前景,其独特优势和应用效果正逐渐改变着茶饮料行业的生产方式。以下是几个关键点,说明了这一技术为何具有如此积极的发展潜力: 1. 高效澄清与保留风味 管式超滤膜具有高精度的过滤能力&#x…...
maven web项目如何定义filter
在 Maven Web 项目中定义一个 Servlet 过滤器(Filter),需要遵循 Java Servlet 规范,并利用 Maven 来管理项目结构和依赖。下面是如何在 Maven Web 项目中定义和配置一个过滤器的基本步骤: 1. 创建过滤器类 首先&…...
如何在MacOS上查看edge/chrome的扩展源码
步骤 进入管理扩展页面点击详细信息复制对应id在命令行键入 open ~/Library/Application Support/Microsoft Edge/Default/Extensions/${你刚刚复制的id} 即可打开访达中对应的更目录 注意 由于原生命令行无法直接处理空格 ,所以需要加转义符\,即:open ~/Librar…...
【学术投稿-2025年计算机视觉研究进展与应用国际学术会议 (ACVRA 2025)】CSS样式解析:行内、内部与外部样式的区别与优先级分析
简介 2025年计算机视觉研究进展与应用(ACVRA 2025)将于2025年2月28-3月2日在中国广州召开,会议将汇聚世界各地的顶尖学者、研究人员和行业专家,聚焦计算机视觉领域的最新研究动态与应用成就。本次会议将探讨前沿技术,…...
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、安装步骤 安装步骤有点独特,先配置虚拟机,然后再虚拟机的虚拟光驱里添加下载的win7。 配置完了之后,点击要运行的虚拟机,然后一直往下走就可以完成系统的安装。 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:数据定义语言。CREATE \ALTER\ DROP \RENAME TRUNCATE DML:数据操作语言。INSERT \DELETE \UPDATE \SELECT(重中之重) DCL:数据控制语言。COMMIT \…...
python自动化测试之Pytest框架之YAML详解以及Parametrize数据驱动!
一、YAML详解 YAML是一种数据类型,它能够和JSON数据相互转化,它本身也是有很多数据类型可以满足我们接口 的参数类型,扩展名可以是.yml或.yaml 作用: 1.全局配置文件 基础路径,数据库信息,账号信息&…...
deepseek的CoT优势、两阶段训练的有效性学习笔记
文章目录 1 DeepSeek的CoT思维链的优势1.2 open-r1的CoT训练数据1.3 ReAct任务与CoT任务适用场景 2 AI推理方向:deepseek与deepmind的两条路线的差异2.1 PRM与ORM的两大学派分支的差异2.2 DeepSeek-R1的两阶段训练概述 1 DeepSeek的CoT思维链的优势 DeepSeek跟之前…...
计算机网络-MPLS转发原理
在上一篇关于 MPLS 基础的文章中,我们了解了 MPLS 的基本概念、术语以及它在网络中的重要性。今天,我们将深入探讨 MPLS 转发的原理与流程,帮助大家更好地理解 MPLS 是如何在实际网络中工作的。 一、MPLS 转发概述 MPLS 转发的本质是将数据…...
本地部署DeepSeek R1并搭建Web UI实现可视化交互的笔记
经过多天的挣扎和卸载了一些软件,终于下定决心在本地部署DeepSeek R1模型。部署和搭建过程非常简单和方便。 一、下载Ollama 进入Ollama官方网站(https://ollama.com),进入下载下载Ollama页面(https://ollama.com/download) 根据电脑的操作…...
港中文腾讯提出可穿戴3D资产生成方法BAG,可自动生成服装和配饰等3D资产如,并适应特定的人体模型。
今天给大家介绍一种名为BAG(Body-Aligned 3D Wearable Asset Generation)的新方法,可以自动生成可穿戴的3D资产,如服装和配饰,以适应特定的人体模型。BAG方法通过构建一个多视图图像扩散模型,生成与人体对齐…...
JUC并发—1.Java集合包底层源码剖析
大纲 1.为什么要对JDK源码剖析 2.ArrayList源码一:基本原理以及优缺点 3.ArrayList源码二:核心方法的原理 4.ArrayList源码三:数组扩容以及元素拷贝 5.LinkedList源码一:优缺点和使用场景 6.LinkedList源码二:双…...
使用Java爬虫获取京东商品评论API接口(JD.item_review)数据
一、引言 在电商领域,商品评论是用户决策的重要参考依据,也是商家优化产品和服务的重要数据来源。京东作为国内领先的电商平台,提供了丰富的API接口供开发者使用,其中JD.item_review接口可以获取商品的评论数据。通过这些数据&am…...
问卷数据分析|SPSS实操之单因素方差分析
适用条件: 检验分类变量和定量变量之间的差异 分类变量数量要大于等于三 具体操作: 1.选择分析--比较平均值--单因素ANOVA检验 2. 下方填分类变量,上方为各个量表数据Z1-Y2 3. 点击选项,选择描述和方差齐性检验 4.此处为结果数…...
【自然语言处理】TextRank 算法提取关键词、短语、句(Python源码实现)
文章目录 一、TextRank 算法提取关键词 [工具包]二、TextRank 算法提取关键短语[工具包]三、TextRank 算法提取关键句[工具包]四、TextRank 算法提取关键句(Python源码实现) 一、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环境,创建新的项目,选择【ASP.Net Core Web 应用(模型-视图-控制器)】如下图所示 编写项目名称 点击创建,进入项目后结构如下所示 wwwroot 文件夹为图片、JS、CSS等静态文件…...
ios通过xib创建控件
之前写过ios动态创建控件及添加事件,纯手工代码写控件,虽然比较灵活,但是就是代码量比较多。这次我们通过xib来创建app下载列表项 AppView.xib。一个imageview,一个label,一个button构成 1.创建AppView.xib 2.再创建xib对应的mode࿰…...
缓存组件<keep-alive>
缓存组件<keep-alive> 1.组件作用 组件, 默认会缓存内部的所有组件实例,当组件需要缓存时首先考虑使用此组件。 2.使用场景 场景1:tab切换时,对应的组件保持原状态,使用keep-alive组件 使用:KeepAlive | Vu…...
SAP ABAP调用DeepSeek API大模型接口
搜索了一下DeepSeek,发现有人已经实现了SAP的对接, 不登录网页,SAP如何使用DeepSeek快速编程,ABAP起飞啦~ 按照对应的注册流程和方法。总算做出了第一个能够直连DeepSeek的API abap程序。 效果不错。 report ZTOOL_ABAP_CALL_D…...
大数据与大模型:数字时代的共生力量
引言:大数据与大模型的崭新时代 在数字化浪潮汹涌澎湃的当下,大数据与大模型无疑是最为耀眼的两颗明星 ,深刻地改变着我们的生活、工作和思维方式。大数据,作为信息时代的宝藏,蕴含着无尽的价值。从电商平台的海量交易…...
服务器使用宝塔面板Docker应用快速部署 DeepSeek-R1模型,实现Open WebUI访问使用
Deepseek这段时间非常火,最新推理模型Deepseek R1,都想装上试一试,特别是部署到服务器教程网上一堆教程好像没几个部署成功靠谱的,先说服务器上下载Ollama就难倒一堆人,每次都超时。今天终于在宝塔看到一篇 应用安装文…...
Qt - 地图相关 —— 3、Qt调用高德在线地图功能示例(附源码)
效果 作者其他相关文章链接: Qt - 地图相关 —— 1、加载百度在线地图(附源码) Qt - 地图相关 —— 2、Qt调用百度在线地图功能示例全集,包含线路规划、地铁线路查询等(附源码) Qt - 地图相关 —— 3、Qt调用…...
Idea集成deepseek生成代码
今天我带大家在idea上安装CodeGpt插件,这个插件可以根据我们的提示词生产代码,我们一起试试。 1、安装插件 打开idea,再点击setting菜单,按以下步骤操作。 安装完成后,一定要点击第四步“ok”。再次点击菜单setting…...
HTTP 请求方式`application/x-www-form-urlencoded` 与 `application/json` 怎么用?有什么区别?
HTTP 请求方式总结:application/x-www-form-urlencoded 与 application/json 在前后端交互中,客户端发送数据到服务器的常见方式有两种:application/x-www-form-urlencoded 和 application/json。本文将详细介绍这两种请求方式的特点、使用方…...
开发指南099-同时传递文件和参数
平台后台接口一般情况下要求传递一个json对象(对应后台需要一个继承RequestInfo的dto类),某些情况下需要同时传递文件和参数,该如何处理呢? 1、前端 const formData new FormData(); formData.append(file, this.f…...
【Pycharm+Git+Gitlab】安装部署(粗糙版)
1、安装Git 2、安装Pycharm(这里选择的是社区版) 3、桌面右键打开Git Bash 1)设置全局用户名(准备连接的Gitlab仓库的访问用户名) git config ---global user.name "username"2)设置全局邮箱&…...
k8s中部署nginx的pod
在当今数字化的浪潮中,容器编排技术成为了构建和管理应用程序的核心力量。Kubernetes(简称 k8s)作为容器编排领域的佼佼者,凭借其强大的自动化部署、扩展和管理能力,深受开发者和运维人员的青睐。而 Nginx 作为一款高性…...
kafka生产者之发送模式与ACK
文章目录 Kafka的发送模式Kafka的ack机制发送模式与ack的关联重试次数总结 在Kafka中,发送模式与ack机制紧密相关,它们共同影响着消息发送的可靠性和性能。 Kafka的发送模式 发后即忘(Fire and Forget):生产者发送消息…...
Clion使用jlink进行程序下载
1. 打开首选项(Preference)的Build, Execution, Deployment里的Toolchains,新建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操作符指针理解
对于初学者来说操作符指针类型、指针、取地址容易混淆,多练就好了。 只需要记住两个符号:&(取内存地址)和*(解引用)。 定义和使用:你可以使用 & 操作符获取一个变量的内存地址&#x…...
MATLAB 生成脉冲序列 pulstran函数使用详解
MATLAB 生成脉冲序列 pulstran函数使用详解 目录 前言 一、参数说明 二、示例一 三、示例二 总结 前言 MATLAB中的pulstran函数用于生成脉冲序列,支持连续或离散脉冲。该函数通过将原型脉冲延迟并相加,生成脉冲序列,适用于信号处理和系统…...