架构之事务性数据存储
引言
在数字化时代,数据已经成为企业最重要的资产之一。而对于需要事务性保证的数据操作,如何确保数据的完整性、一致性和可靠性,成为架构设计的核心挑战。事务性数据存储架构法则强调:对于需要原子性、一致性、隔离性、持久性(ACID)事务保证的数据操作场景,使用关系型数据库管理系统(RDBMS)/SQL数据库,通过完善的事务机制确保数据的完整性和业务的一致性。
事务性数据操作是业务系统的核心命脉。金融交易、订单处理、库存管理、账户系统等关键业务都依赖于强事务保证。一旦数据一致性出现问题,不仅会导致业务损失,更可能引发严重的信任危机。
事务性数据存储的核心理念
为什么需要事务性保证?
事务性保证能够有效解决上述挑战:
- 原子性保证:确保操作要么全部成功,要么全部失败,避免数据不一致状态
- 一致性维护:通过约束和规则保证数据始终处于有效状态
- 隔离性保护:防止并发操作相互干扰,确保数据正确性
- 持久性承诺:一旦事务提交,数据永久保存,不受系统故障影响
ACID特性详解
事务性数据存储架构设计原则
1. 强一致性原则
确保数据在任何时刻都保持一致状态,不允许出现中间状态或不一致情况。
// 强一致性事务实现
@Service
public class TransactionalBankingService {
@Autowired
private AccountRepository accountRepository;
@Autowired
private TransactionRepository transactionRepository;
/**
* 银行转账:强一致性要求
*/
@Transactional(isolation = Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED)
public TransferResult transferMoney(TransferRequest request) {
log.info("开始转账事务: from={}, to={}, amount={}",
request.getFromAccount(), request.getToAccount(), request.getAmount());
try {
// 1. 获取账户信息(加锁)
Account fromAccount = accountRepository.findByAccountNumberForUpdate(request.getFromAccount());
Account toAccount = accountRepository.findByAccountNumberForUpdate(request.getToAccount());
// 2. 验证账户状态
validateAccountStatus(fromAccount, toAccount);
// 3. 检查余额充足性
if (fromAccount.getBalance().compareTo(request.getAmount()) < 0) {
throw new InsufficientBalanceException("账户余额不足");
}
// 4. 执行转账操作
// 4.1 扣减源账户余额
BigDecimal newFromBalance = fromAccount.getBalance().subtract(request.getAmount());
fromAccount.setBalance(newFromBalance);
accountRepository.update(fromAccount);
// 4.2 增加目标账户余额
BigDecimal newToBalance = toAccount.getBalance().add(request.getAmount());
toAccount.setBalance(newToBalance);
accountRepository.update(toAccount);
// 5. 记录交易明细
TransactionRecord transaction = TransactionRecord.builder()
.transactionId(generateTransactionId())
.fromAccount(request.getFromAccount())
.toAccount(request.getToAccount())
.amount(request.getAmount())
.transactionType(TransactionType.TRANSFER)
.status(TransactionStatus.COMPLETED)
.createTime(LocalDateTime.now())
.build();
transactionRepository.save(transaction);
// 6. 记录账户变动历史
recordAccountHistory(fromAccount, request.getAmount(), TransactionType.DEBIT);
recordAccountHistory(toAccount, request.getAmount(), TransactionType.CREDIT);
log.info("转账事务成功: transactionId={}", transaction.getTransactionId());
return TransferResult.success(transaction.getTransactionId());
} catch (Exception e) {
log.error("转账事务失败", e);
throw new TransactionException("转账操作失败", e);
}
}
/**
* 验证账户状态
*/
private void validateAccountStatus(Account fromAccount, Account toAccount) {
// 检查账户是否存在
if (fromAccount == null || toAccount == null) {
throw new AccountNotFoundException("账户不存在");
}
// 检查账户状态
if (fromAccount.getStatus() != AccountStatus.ACTIVE) {
throw new AccountInactiveException("源账户状态异常");
}
if (toAccount.getStatus() != AccountStatus.ACTIVE) {
throw new AccountInactiveException("目标账户状态异常");
}
// 检查账户类型是否支持转账
if (!isTransferAllowed(fromAccount.getAccountType(), toAccount.getAccountType())) {
throw new InvalidAccountTypeException("账户类型不支持转账");
}
}
}
2. 隔离级别选择原则
根据业务场景选择合适的隔离级别,平衡一致性和性能。
// 隔离级别选择策略
@Component
public class IsolationLevelSelector {
/**
* 根据业务场景选择隔离级别
*/
public IsolationLevel selectIsolationLevel(BusinessScenario scenario) {
switch (scenario.getType()) {
case BANKING_TRANSFER:
// 银行转账:最高隔离级别,防止任何并发问题
return IsolationLevel.SERIALIZABLE;
case INVENTORY_MANAGEMENT:
// 库存管理:防止幻读,确保库存准确性
return IsolationLevel.REPEATABLE_READ;
case USER_REGISTRATION:
// 用户注册:防止不可重复读,确保用户名唯一性
return IsolationLevel.READ_COMMITTED;
case REPORT_GENERATION:
// 报表生成:允许读取已提交数据,提高并发性
return IsolationLevel.READ_COMMITTED;
case LOG_RECORDING:
// 日志记录:允许读取未提交数据,追求最高性能
return IsolationLevel.READ_UNCOMMITTED;
default:
// 默认使用READ_COMMITTED
return IsolationLevel.READ_COMMITTED;
}
}
}
// 不同隔离级别的实现示例
@Repository
public class IsolationLevelDemoRepository {
/**
* READ_UNCOMMITTED:读取未提交数据
* 适用场景:对数据一致性要求不高,追求极致性能
*/
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public List<LogEntry> getRecentLogs() {
// 可以读取其他事务未提交的数据
return jdbcTemplate.query(
"SELECT * FROM system_logs ORDER BY create_time DESC LIMIT 100",
new LogEntryRowMapper()
);
}
/**
* READ_COMMITTED:读取已提交数据(大多数数据库的默认级别)
* 适用场景:一般业务查询,防止脏读
*/
@Transactional(isolation = Isolation.READ_COMMITTED)
public UserProfile getUserProfile(Long userId) {
// 只能读取已提交的数据,防止脏读
return jdbcTemplate.queryForObject(
"SELECT * FROM user_profiles WHERE user_id = ?",
new Object[]{userId},
new UserProfileRowMapper()
);
}
/**
* REPEATABLE_READ:可重复读
* 适用场景:需要多次读取同一数据,确保数据一致性
*/
@Transactional(isolation = Isolation.REPEATABLE_READ)
public OrderStatistics calculateOrderStatistics(Long userId) {
// 在同一个事务中,多次读取同一数据结果一致
BigDecimal totalAmount = jdbcTemplate.queryForObject(
"SELECT SUM(amount) FROM orders WHERE user_id = ?",
new Object[]{userId},
BigDecimal.class
);
Integer orderCount = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM orders WHERE user_id = ?",
new Object[]{userId},
Integer.class
);
return OrderStatistics.builder()
.userId(userId)
.totalAmount(totalAmount != null ? totalAmount : BigDecimal.ZERO)
.orderCount(orderCount != null ? orderCount : 0)
.build();
}
/**
* SERIALIZABLE:串行化
* 适用场景:金融交易,需要最高级别的数据一致性
*/
@Transactional(isolation = Isolation.SERIALIZABLE)
public boolean transferInventory(Long productId, Integer quantity, String fromWarehouse, String toWarehouse) {
// 完全串行化执行,防止所有并发问题
// 1. 检查源仓库库存
Integer fromStock = jdbcTemplate.queryForObject(
"SELECT stock_quantity FROM warehouse_inventory WHERE product_id = ? AND warehouse_code = ? FOR UPDATE",
new Object[]{productId, fromWarehouse},
Integer.class
);
if (fromStock == null || fromStock < quantity) {
throw new InsufficientInventoryException("源仓库库存不足");
}
// 2. 扣减源仓库库存
jdbcTemplate.update(
"UPDATE warehouse_inventory SET stock_quantity = stock_quantity - ? WHERE product_id = ? AND warehouse_code = ?",
quantity, productId, fromWarehouse
);
// 3. 增加目标仓库库存
Integer updatedRows = jdbcTemplate.update(
"UPDATE warehouse_inventory SET stock_quantity = stock_quantity + ? WHERE product_id = ? AND warehouse_code = ?",
quantity, productId, toWarehouse
);
// 4. 如果目标仓库没有该商品,插入新记录
if (updatedRows == 0) {
jdbcTemplate.update(
"INSERT INTO warehouse_inventory (product_id, warehouse_code, stock_quantity) VALUES (?, ?, ?)",
productId, toWarehouse, quantity
);
}
// 5. 记录库存移动历史
recordInventoryMovement(productId, quantity, fromWarehouse, toWarehouse);
return true;
}
}
3. 异常处理原则
建立完善的异常处理机制,确保事务的正确回滚和数据的一致性。
// 事务异常处理机制
@Service
public class TransactionalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(TransactionalExceptionHandler.class);
/**
* 订单处理:完整的事务异常处理示例
*/
@Transactional(rollbackFor = {BusinessException.class, SystemException.class})
public OrderProcessingResult processOrder(OrderRequest request) {
String orderId = null;
OrderStatus originalStatus = null;
try {
// 1. 创建订单
Order order = createOrder(request);
orderId = order.getOrderId();
log.info("订单创建成功: orderId={}", orderId);
// 2. 扣减库存
deductInventory(order);
log.info("库存扣减成功: orderId={}", orderId);
// 3. 计算价格
calculatePrice(order);
log.info("价格计算成功: orderId={}", orderId);
// 4. 应用促销
applyPromotion(order);
log.info("促销应用成功: orderId={}", orderId);
// 5. 更新订单状态
originalStatus = order.getStatus();
updateOrderStatus(order, OrderStatus.PROCESSING);
log.info("订单状态更新成功: orderId={}", orderId);
// 6. 发送通知
sendOrderNotification(order);
log.info("通知发送成功: orderId={}", orderId);
return OrderProcessingResult.success(orderId);
} catch (BusinessException e) {
// 业务异常:记录日志,事务会自动回滚
log.error("订单处理业务异常: orderId={}, error={}", orderId, e.getMessage());
throw e; // 重新抛出,触发事务回滚
} catch (DataAccessException e) {
// 数据访问异常:可能是数据库连接问题
log.error("数据访问异常: orderId={}", orderId, e);
throw new SystemException("数据库操作失败", e);
} catch (Exception e) {
// 未知异常:记录详细信息
log.error("订单处理未知异常: orderId={}", orderId, e);
throw new SystemException("系统处理异常", e);
} finally {
// 清理资源:关闭连接、释放锁等
cleanupResources(orderId);
}
}
/**
* 库存扣减:特定的异常处理策略
*/
private void deductInventory(Order order) {
try {
inventoryService.deductInventory(order.getItems());
} catch (InsufficientInventoryException e) {
// 库存不足:业务异常,需要回滚
log.warn("库存不足: orderId={}, productId={}, required={}, available={}",
order.getOrderId(), e.getProductId(), e.getRequiredQuantity(), e.getAvailableQuantity());
throw new BusinessException("商品库存不足", e);
} catch (InventoryLockException e) {
// 库存锁定失败:可能是并发冲突
log.error("库存锁定失败: orderId={}", order.getOrderId(), e);
throw new BusinessException("商品正在被其他用户购买,请稍后重试", e);
} catch (Exception e) {
// 其他库存相关异常
log.error("库存扣减异常: orderId={}", order.getOrderId(), e);
throw new SystemException("库存系统异常", e);
}
}
/**
* 价格计算:处理复杂的业务异常
*/
private void calculatePrice(Order order) {
try {
priceService.calculateOrderPrice(order);
} catch (PriceExpiredException e) {
// 价格已过期:需要重新获取最新价格
log.warn("价格已过期: orderId={}, productId={}", order.getOrderId(), e.getProductId());
// 尝试重新获取价格
boolean priceUpdated = priceService.refreshProductPrice(e.getProductId());
if (priceUpdated) {
// 价格更新成功,重新计算
priceService.calculateOrderPrice(order);
} else {
throw new BusinessException("商品价格已变动,请重新下单", e);
}
} catch (PromotionExpiredException e) {
// 促销已过期:移除促销重新计算
log.warn("促销已过期: orderId={}, promotionId={}", order.getOrderId(), e.getPromotionId());
// 移除过期促销
order.removePromotion(e.getPromotionId());
// 重新计算价格
priceService.calculateOrderPrice(order);
} catch (Exception e) {
log.error("价格计算异常: orderId={}", order.getOrderId(), e);
throw new SystemException("价格计算失败", e);
}
}
/**
* 事务补偿机制
*/
public void compensateFailedOrder(String orderId, OrderStatus originalStatus) {
log.info("开始订单补偿: orderId={}, originalStatus={}", orderId, originalStatus);
try {
Order order = orderRepository.findByOrderId(orderId);
if (order == null) {
log.warn("订单不存在,无法补偿: orderId={}", orderId);
return;
}
// 1. 恢复库存
if (order.getInventoryDeducted()) {
inventoryService.restoreInventory(order.getItems());
log.info("库存恢复成功: orderId={}", orderId);
}
// 2. 恢复优惠券
if (order.getCouponsUsed() != null && !order.getCouponsUsed().isEmpty()) {
couponService.restoreCoupons(order.getUserId(), order.getCouponsUsed());
log.info("优惠券恢复成功: orderId={}", orderId);
}
// 3. 恢复积分
if (order.getPointsDeducted() > 0) {
pointService.restorePoints(order.getUserId(), order.getPointsDeducted());
log.info("积分恢复成功: orderId={}", orderId);
}
// 4. 更新订单状态
order.setStatus(OrderStatus.CANCELLED);
order.setCancelTime(LocalDateTime.now());
order.setCancelReason("系统异常,自动取消");
orderRepository.update(order);
log.info("订单补偿完成: orderId={}", orderId);
} catch (Exception e) {
log.error("订单补偿失败: orderId={}", orderId, e);
// 发送告警,需要人工干预
alertService.sendCompensationFailureAlert(orderId, e.getMessage());
}
}
}
事务性数据存储核心技术
1. 并发控制机制
通过锁机制和多版本并发控制(MVCC)确保事务的隔离性。
// 并发控制实现
@Component
public class ConcurrencyControlService {
@Autowired
private LockManager lockManager;
/**
* 悲观锁:适用于高冲突场景
*/
@Transactional
public boolean deductInventoryWithPessimisticLock(Long productId, Integer quantity) {
// 使用SELECT FOR UPDATE加锁
ProductInventory inventory = inventoryRepository.findByProductIdForUpdate(productId);
if (inventory.getAvailableQuantity() < quantity) {
return false;
}
// 扣减库存
inventory.setAvailableQuantity(inventory.getAvailableQuantity() - quantity);
inventoryRepository.update(inventory);
return true;
}
/**
* 乐观锁:适用于低冲突场景
*/
@Transactional
public boolean updateUserProfileWithOptimisticLock(UserProfile profile) {
// 获取当前版本号
UserProfile currentProfile = userProfileRepository.findByUserId(profile.getUserId());
Integer currentVersion = currentProfile.getVersion();
// 更新时检查版本号
int updatedRows = userProfileRepository.updateWithVersion(profile, currentVersion);
if (updatedRows == 0) {
// 版本号不匹配,说明数据已被其他事务修改
throw new OptimisticLockingFailureException("数据已被其他用户修改,请刷新后重试");
}
return true;
}
/**
* 分布式锁:跨服务并发控制
*/
public boolean processOrderWithDistributedLock(String orderId) {
String lockKey = "order_processing:" + orderId;
String lockValue = UUID.randomUUID().toString();
try {
// 获取分布式锁,超时时间30秒
boolean locked = distributedLock.tryLock(lockKey, lockValue, 30, TimeUnit.SECONDS);
if (!locked) {
log.warn("获取分布式锁失败: orderId={}", orderId);
return false;
}
// 处理订单
return processOrder(orderId);
} finally {
// 释放分布式锁
distributedLock.unlock(lockKey, lockValue);
}
}
/**
* MVCC读取:非阻塞读操作
*/
@Transactional(isolation = Isolation.READ_COMMITTED)
public AccountStatement generateAccountStatement(Long accountId, LocalDate startDate, LocalDate endDate) {
// MVCC允许非阻塞读取,不会阻塞其他事务的写操作
List<TransactionRecord> transactions = transactionRepository.findByAccountIdAndDateRange(
accountId, startDate, endDate
);
// 计算期初余额(使用快照读)
BigDecimal openingBalance = accountRepository.getBalanceAtDate(accountId, startDate.minusDays(1));
// 计算期末余额
BigDecimal closingBalance = openingBalance.add(
transactions.stream()
.map(TransactionRecord::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add)
);
return AccountStatement.builder()
.accountId(accountId)
.startDate(startDate)
.endDate(endDate)
.openingBalance(openingBalance)
.closingBalance(closingBalance)
.transactions(transactions)
.build();
}
}
2. 分布式事务处理
在微服务架构下处理跨服务的事务一致性。
// 分布式事务实现
@Service
public class DistributedTransactionService {
@Autowired
private SagaTransactionManager sagaManager;
@Autowired
private TccTransactionManager tccManager;
/**
* Saga模式:适用于长事务
*/
public SagaTransaction createOrderSaga(CreateOrderRequest request) {
SagaTransaction saga = SagaTransaction.builder()
.transactionId(generateTransactionId())
.transactionType("ORDER_CREATION")
.status(SagaStatus.STARTED)
.build();
// 定义Saga步骤
saga.addStep(SagaStep.builder()
.stepName("CREATE_ORDER")
.serviceName("order-service")
.actionMethod("createOrder")
.compensateMethod("cancelOrder")
.build());
saga.addStep(SagaStep.builder()
.stepName("DEDUCT_INVENTORY")
.serviceName("inventory-service")
.actionMethod("deductInventory")
.compensateMethod("restoreInventory")
.build());
saga.addStep(SagaStep.builder()
.stepName("PROCESS_PAYMENT")
.serviceName("payment-service")
.actionMethod("processPayment")
.compensateMethod("refundPayment")
.build());
// 执行Saga事务
return sagaManager.executeSaga(saga, request);
}
/**
* TCC模式:Try-Confirm-Cancel
*/
public TccTransaction processOrderTcc(CreateOrderRequest request) {
String transactionId = generateTransactionId();
try {
// Phase 1: Try阶段
TccTransaction tcc = TccTransaction.builder()
.transactionId(transactionId)
.status(TccStatus.TRYING)
.build();
// Try:预留资源
boolean tryResult = executeTryPhase(tcc, request);
if (!tryResult) {
throw new TccException("Try阶段失败");
}
// Phase 2: Confirm阶段
tcc.setStatus(TccStatus.CONFIRMING);
boolean confirmResult = executeConfirmPhase(tcc);
if (!confirmResult) {
throw new TccException("Confirm阶段失败");
}
tcc.setStatus(TccStatus.CONFIRMED);
return tcc;
} catch (Exception e) {
log.error("TCC事务失败,开始Cancel阶段: transactionId={}", transactionId, e);
// 执行Cancel阶段
try {
executeCancelPhase(transactionId);
} catch (Exception cancelException) {
log.error("Cancel阶段也失败: transactionId={}", transactionId, cancelException);
// 发送告警,需要人工处理
alertService.sendManualInterventionAlert(transactionId);
}
throw new TransactionException("订单处理失败", e);
}
}
/**
* 最大努力通知:适用于最终一致性要求
*/
public void processOrderWithBestEffort(CreateOrderRequest request) {
String orderId = generateOrderId();
try {
// 1. 本地事务:创建订单
Order order = createOrderInLocalTransaction(request, orderId);
// 2. 发送消息到消息队列
OrderCreatedEvent event = OrderCreatedEvent.builder()
.orderId(orderId)
.userId(request.getUserId())
.items(request.getItems())
.totalAmount(order.getTotalAmount())
.build();
messageQueueService.sendOrderCreatedEvent(event);
// 3. 等待下游服务处理
// 下游服务通过消息队列异步处理库存扣减、支付等操作
log.info("订单创建成功,等待下游处理: orderId={}", orderId);
} catch (Exception e) {
log.error("订单创建失败: orderId={}", orderId, e);
throw new OrderCreationException("订单创建失败", e);
}
}
/**
* 可靠消息最终一致性
*/
@Transactional
public void processOrderWithReliableMessage(CreateOrderRequest request) {
String orderId = generateOrderId();
try {
// 1. 准备消息
OrderCreatedEvent event = OrderCreatedEvent.builder()
.orderId(orderId)
.userId(request.getUserId())
.items(request.getItems())
.build();
// 2. 本地事务:创建订单 + 存储消息
Order order = transactionTemplate.execute(status -> {
// 创建订单
Order newOrder = createOrder(request, orderId);
// 存储消息到本地消息表
OutboxMessage message = OutboxMessage.builder()
.messageId(generateMessageId())
.aggregateId(orderId)
.eventType("OrderCreated")
.payload(objectMapper.writeValueAsString(event))
.status(MessageStatus.PENDING)
.createTime(LocalDateTime.now())
.build();
outboxMessageRepository.save(message);
return newOrder;
});
// 3. 异步发送消息
messageRelayService.relayMessages();
log.info("可靠消息事务成功: orderId={}", orderId);
} catch (Exception e) {
log.error("可靠消息事务失败: orderId={}", orderId, e);
throw new TransactionException("订单处理失败", e);
}
}
}
3. 事务监控与诊断
建立完善的事务监控体系,及时发现和解决事务相关问题。
// 事务监控服务
@Component
public class TransactionMonitorService {
private static final Logger log = LoggerFactory.getLogger(TransactionMonitorService.class);
@Autowired
private MetricsCollector metricsCollector;
@Autowired
private AlertService alertService;
/**
* 事务性能监控
*/
@EventListener
public void handleTransactionCompletion(TransactionCompletionEvent event) {
TransactionInfo txInfo = event.getTransactionInfo();
// 记录事务执行时间
long duration = txInfo.getCompletionTime() - txInfo.getStartTime();
metricsCollector.recordTransactionDuration(txInfo.getTransactionType(), duration);
// 记录事务结果
if (txInfo.isSuccessful()) {
metricsCollector.incrementTransactionSuccess(txInfo.getTransactionType());
} else {
metricsCollector.incrementTransactionFailure(txInfo.getTransactionType());
log.warn("事务失败: transactionId={}, type={}, error={}",
txInfo.getTransactionId(), txInfo.getTransactionType(), txInfo.getErrorMessage());
}
// 慢事务告警
if (duration > getSlowTransactionThreshold(txInfo.getTransactionType())) {
alertService.sendSlowTransactionAlert(txInfo, duration);
}
}
/**
* 死锁检测与处理
*/
@Scheduled(fixedDelay = 60000) // 每分钟检查一次
public void detectDeadlocks() {
try {
List<DeadlockInfo> deadlocks = databaseAdminService.detectDeadlocks();
for (DeadlockInfo deadlock : deadlocks) {
log.error("检测到死锁: victim={}, participants={}",
deadlock.getVictimTransaction(), deadlock.getParticipantTransactions());
// 记录死锁信息
metricsCollector.incrementDeadlockCount();
// 发送死锁告警
alertService.sendDeadlockAlert(deadlock);
// 分析死锁原因
analyzeDeadlockCause(deadlock);
}
} catch (Exception e) {
log.error("死锁检测失败", e);
}
}
/**
* 事务超时监控
*/
@Scheduled(fixedDelay = 30000) // 每30秒检查一次
public void monitorTransactionTimeouts() {
try {
List<TransactionInfo> activeTransactions = transactionManager.getActiveTransactions();
long currentTime = System.currentTimeMillis();
for (TransactionInfo tx : activeTransactions) {
long duration = currentTime - tx.getStartTime();
// 检查是否超时
if (duration > getTransactionTimeout(tx.getTransactionType())) {
log.warn("发现超时事务: transactionId={}, duration={}ms, type={}",
tx.getTransactionId(), duration, tx.getTransactionType());
// 强制回滚超时事务
try {
transactionManager.rollbackTransaction(tx.getTransactionId());
log.info("超时事务已回滚: transactionId={}", tx.getTransactionId());
} catch (Exception e) {
log.error("回滚超时事务失败: transactionId={}", tx.getTransactionId(), e);
alertService.sendTransactionRollbackFailureAlert(tx.getTransactionId(), e.getMessage());
}
}
}
} catch (Exception e) {
log.error("事务超时监控失败", e);
}
}
/**
* 连接池监控
*/
@Scheduled(fixedDelay = 10000) // 每10秒检查一次
public void monitorConnectionPool() {
try {
ConnectionPoolMetrics metrics = dataSource.getConnectionPoolMetrics();
// 检查连接池使用率
double usageRate = (double) metrics.getActiveConnections() / metrics.getMaxConnections();
if (usageRate > 0.9) {
log.warn("连接池使用率过高: usageRate={}, active={}, max={}",
usageRate, metrics.getActiveConnections(), metrics.getMaxConnections());
alertService.sendConnectionPoolHighUsageAlert(metrics);
}
// 检查等待队列长度
if (metrics.getWaitingConnections() > 50) {
log.warn("连接池等待队列过长: waiting={}", metrics.getWaitingConnections());
alertService.sendConnectionPoolQueueOverflowAlert(metrics);
}
// 记录连接池指标
metricsCollector.recordConnectionPoolMetrics(metrics);
} catch (Exception e) {
log.error("连接池监控失败", e);
}
}
/**
* 长事务检测
*/
@Scheduled(fixedDelay = 120000) // 每2分钟检查一次
public void detectLongRunningTransactions() {
try {
List<TransactionInfo> longRunningTxs = transactionManager.getLongRunningTransactions(
getLongTransactionThreshold()
);
for (TransactionInfo tx : longRunningTxs) {
log.warn("发现长事务: transactionId={}, duration={}ms, type={}, sql={}",
tx.getTransactionId(),
System.currentTimeMillis() - tx.getStartTime(),
tx.getTransactionType(),
tx.getCurrentSql()
);
// 发送长事务告警
alertService.sendLongRunningTransactionAlert(tx);
// 记录长事务信息
metricsCollector.recordLongRunningTransaction(tx);
}
} catch (Exception e) {
log.error("长事务检测失败", e);
}
}
}
事务性数据存储最佳实践
1. 事务设计最佳实践
// 事务设计模式
@Component
public class TransactionDesignPatterns {
/**
* 模式1:事务脚本模式
* 适用场景:简单业务逻辑
*/
@Transactional
public void transferMoneyScript(Long fromAccountId, Long toAccountId, BigDecimal amount) {
// 1. 验证参数
validateTransferParameters(fromAccountId, toAccountId, amount);
// 2. 获取账户信息
Account fromAccount = accountRepository.findById(fromAccountId);
Account toAccount = accountRepository.findById(toAccountId);
// 3. 业务验证
validateAccounts(fromAccount, toAccount, amount);
// 4. 执行转账
performTransfer(fromAccount, toAccount, amount);
// 5. 记录日志
recordTransferLog(fromAccountId, toAccountId, amount);
}
/**
* 模式2:领域模型模式
* 适用场景:复杂业务逻辑
*/
@Transactional
public void processOrderDomainModel(OrderRequest request) {
// 1. 加载聚合根
Order order = orderRepository.findById(request.getOrderId());
// 2. 执行业务操作(在领域对象内部处理业务规则)
order.process(request);
// 3. 保存聚合根(自动保存所有变更)
orderRepository.save(order);
// 4. 发布领域事件
domainEventPublisher.publish(order.getDomainEvents());
}
/**
* 模式3:工作单元模式
* 适用场景:需要批量处理的场景
*/
@Transactional
public void batchProcessOrders(List<OrderRequest> requests) {
// 创建工作单元
UnitOfWork unitOfWork = unitOfWorkFactory.create();
try {
for (OrderRequest request : requests) {
// 处理每个订单
Order order = processSingleOrder(request);
// 注册到工作单元
unitOfWork.registerNew(order);
// 批量处理,避免内存溢出
if (unitOfWork.getChangeCount() >= BATCH_SIZE) {
unitOfWork.commit();
unitOfWork.clear();
}
}
// 提交剩余变更
if (unitOfWork.hasChanges()) {
unitOfWork.commit();
}
} catch (Exception e) {
// 回滚所有变更
unitOfWork.rollback();
throw new BatchProcessingException("批量处理失败", e);
}
}
/**
* 模式4:乐观离线锁模式
* 适用场景:长事务、Web应用
*/
@Transactional
public void updateUserProfileWithOptimisticLock(UserProfileRequest request, Integer version) {
// 1. 验证版本号
UserProfile currentProfile = userProfileRepository.findByUserId(request.getUserId());
if (!currentProfile.getVersion().equals(version)) {
throw new OptimisticLockingException(
String.format("数据已被其他用户修改,当前版本:%d,请求版本:%d",
currentProfile.getVersion(), version)
);
}
// 2. 更新数据
currentProfile.update(request);
// 3. 保存并自动增加版本号
userProfileRepository.update(currentProfile);
log.info("用户资料更新成功: userId={}, newVersion={}",
request.getUserId(), currentProfile.getVersion());
}
}
2. 性能优化策略
# 数据库性能优化配置
performance_optimization:
# 连接池优化
connection_pool:
hikari:
maximum_pool_size: 50 # 最大连接数
minimum_idle: 10 # 最小空闲连接
connection_timeout: 30000 # 连接超时时间
idle_timeout: 600000 # 空闲超时时间
max_lifetime: 1800000 # 最大生命周期
leak_detection_threshold: 60000 # 泄露检测阈值
# 事务超时设置
transaction_timeout:
default: 30 # 默认事务超时(秒)
long_running: 300 # 长事务超时(秒)
batch_processing: 600 # 批处理超时(秒)
# 数据库优化
database:
mysql:
innodb_buffer_pool_size: "8G" # InnoDB缓冲池大小
innodb_log_file_size: "2G" # InnoDB日志文件大小
innodb_flush_log_at_trx_commit: 2 # 事务提交刷新策略
innodb_lock_wait_timeout: 50 # 锁等待超时时间
transaction_isolation: "READ-COMMITTED" # 事务隔离级别
# 读写分离配置
read_write_splitting:
master:
url: "jdbc:mysql://master-db:3306/myapp"
username: "root"
password: "password"
driver_class_name: "com.mysql.cj.jdbc.Driver"
slaves:
- url: "jdbc:mysql://slave1-db:3306/myapp"
username: "root"
password: "password"
- url: "jdbc:mysql://slave2-db:3306/myapp"
username: "root"
password: "password"
# 分库分表配置
sharding:
databases:
- name: "db0"
url: "jdbc:mysql://db0-host:3306/myapp"
- name: "db1"
url: "jdbc:mysql://db1-host:3306/myapp"
tables:
user:
actual_data_nodes: "db${0..1}.user_${0..3}"
database_strategy:
type: "INLINE"
props:
algorithm_expression: "db${user_id % 2}"
table_strategy:
type: "INLINE"
props:
algorithm_expression: "user_${user_id % 4}"
3. 监控告警配置
# Prometheus事务监控配置
groups:
- name: transaction_monitoring
rules:
# 事务失败率告警
- alert: TransactionFailureRateHigh
expr: rate(transaction_failures_total[5m]) / rate(transaction_total[5m]) > 0.05
for: 2m
labels:
severity: warning
annotations:
summary: "事务失败率过高"
description: "事务失败率 {{ $value | humanizePercentage }}"
# 事务超时告警
- alert: TransactionTimeoutHigh
expr: rate(transaction_timeouts_total[5m]) > 10
for: 1m
labels:
severity: critical
annotations:
summary: "事务超时数量过高"
description: "事务超时数 {{ $value }}/秒"
# 死锁告警
- alert: DatabaseDeadlockDetected
expr: increase(mysql_global_status_innodb_deadlocks[1m]) > 0
for: 0m
labels:
severity: warning
annotations:
summary: "检测到数据库死锁"
description: "InnoDB死锁数量 {{ $value }}"
# 长事务告警
- alert: LongRunningTransaction
expr: mysql_info_schema_innodb_trx_trx_duration_seconds > 300
for: 1m
labels:
severity: warning
annotations:
summary: "发现长事务"
description: "事务运行时间 {{ $value }}秒"
# 锁等待告警
- alert: DatabaseLockWaitHigh
expr: mysql_global_status_innodb_row_lock_waits > 100
for: 2m
labels:
severity: warning
annotations:
summary: "数据库锁等待数量过高"
description: "InnoDB行锁等待数 {{ $value }}"
# 连接池使用率告警
- alert: ConnectionPoolUsageHigh
expr: hikaricp_connections_active / hikaricp_connections_max > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "连接池使用率过高"
description: "HikariCP连接池使用率 {{ $value | humanizePercentage }}"
# 事务响应时间告警
- alert: TransactionResponseTimeHigh
expr: histogram_quantile(0.95, rate(transaction_duration_seconds_bucket[5m])) > 5
for: 3m
labels:
severity: warning
annotations:
summary: "事务响应时间过长"
description: "事务95分位响应时间 {{ $value }}秒"
事务性数据存储实践案例
1. 银行核心系统事务设计
// 银行核心系统事务处理
@Service
public class CoreBankingTransactionService {
private static final Logger log = LoggerFactory.getLogger(CoreBankingTransactionService.class);
@Autowired
private AccountRepository accountRepository;
@Autowired
private TransactionRepository transactionRepository;
@Autowired
private AuditRepository auditRepository;
/**
* 核心转账业务:最高级别的事务保证
*/
@Transactional(
isolation = Isolation.SERIALIZABLE,
propagation = Propagation.REQUIRED,
timeout = 30,
rollbackFor = {BankingException.class, SystemException.class}
)
public BankingTransactionResult processCoreTransfer(TransferRequest request) {
String transactionId = generateTransactionId();
log.info("开始核心转账事务: transactionId={}, from={}, to={}, amount={}",
transactionId, request.getFromAccount(), request.getToAccount(), request.getAmount());
try {
// 1. 参数验证
validateTransferRequest(request);
// 2. 账户锁定(防止并发)
Account fromAccount = accountRepository.lockAccount(request.getFromAccount());
Account toAccount = accountRepository.lockAccount(request.getToAccount());
// 3. 账户状态检查
validateAccountForTransfer(fromAccount, toAccount);
// 4. 余额检查
if (fromAccount.getAvailableBalance().compareTo(request.getAmount()) < 0) {
throw new InsufficientBalanceException(
String.format("账户余额不足: account=%s, balance=%s, required=%s",
fromAccount.getAccountNumber(), fromAccount.getAvailableBalance(), request.getAmount())
);
}
// 5. 执行转账
// 5.1 扣减源账户
BigDecimal newFromBalance = fromAccount.getAvailableBalance().subtract(request.getAmount());
fromAccount.setAvailableBalance(newFromBalance);
fromAccount.setLastTransactionTime(LocalDateTime.now());
accountRepository.update(fromAccount);
// 5.2 增加目标账户
BigDecimal newToBalance = toAccount.getAvailableBalance().add(request.getAmount());
toAccount.setAvailableBalance(newToBalance);
toAccount.setLastTransactionTime(LocalDateTime.now());
accountRepository.update(toAccount);
// 6. 记录交易明细
BankingTransaction bankingTx = BankingTransaction.builder()
.transactionId(transactionId)
.transactionType(TransactionType.TRANSFER)
.fromAccount(request.getFromAccount())
.toAccount(request.getToAccount())
.amount(request.getAmount())
.currency(request.getCurrency())
.status(TransactionStatus.COMPLETED)
.description(request.getDescription())
.createTime(LocalDateTime.now())
.build();
transactionRepository.save(bankingTx);
// 7. 记录账户流水
recordAccountEntry(fromAccount, request.getAmount().negate(), transactionId, "转账支出");
recordAccountEntry(toAccount, request.getAmount(), transactionId, "转账收入");
// 8. 审计记录
recordAuditLog(bankingTx, "核心转账完成");
// 9. 风险监控
riskMonitorService.monitorTransaction(bankingTx);
log.info("核心转账事务成功: transactionId={}", transactionId);
return BankingTransactionResult.success(transactionId);
} catch (BankingException e) {
log.error("银行业务异常: transactionId={}, error={}", transactionId, e.getMessage());
throw e;
} catch (Exception e) {
log.error("核心转账系统异常: transactionId={}", transactionId, e);
throw new SystemException("系统处理异常", e);
}
}
/**
* 批量转账处理
*/
@Transactional
public BatchTransferResult processBatchTransfer(BatchTransferRequest request) {
log.info("开始批量转账: batchId={}, count={}", request.getBatchId(), request.getTransfers().size());
List<TransferResult> results = new ArrayList<>();
int successCount = 0;
int failureCount = 0;
try {
// 1. 验证批量转账权限
validateBatchTransferPermission(request);
// 2. 预检查所有账户
preValidateAccounts(request);
// 3. 处理每笔转账
for (TransferRequest transfer : request.getTransfers()) {
try {
TransferResult result = processSingleTransfer(transfer);
results.add(result);
if (result.isSuccess()) {
successCount++;
} else {
failureCount++;
}
} catch (Exception e) {
log.error("单笔转账失败: transfer={}", transfer, e);
results.add(TransferResult.failed(transfer.getRequestId(), e.getMessage()));
failureCount++;
}
}
// 4. 记录批量转账结果
BatchTransferRecord batchRecord = BatchTransferRecord.builder()
.batchId(request.getBatchId())
.totalCount(request.getTransfers().size())
.successCount(successCount)
.failureCount(failureCount)
.totalAmount(calculateTotalAmount(request.getTransfers()))
.status(failureCount == 0 ? BatchStatus.ALL_SUCCESS :
successCount == 0 ? BatchStatus.ALL_FAILED : BatchStatus.PARTIAL_SUCCESS)
.createTime(LocalDateTime.now())
.build();
batchTransferRepository.save(batchRecord);
log.info("批量转账完成: batchId={}, success={}, failure={}",
request.getBatchId(), successCount, failureCount);
return BatchTransferResult.builder()
.batchId(request.getBatchId())
.results(results)
.successCount(successCount)
.failureCount(failureCount)
.status(batchRecord.getStatus())
.build();
} catch (Exception e) {
log.error("批量转账异常: batchId={}", request.getBatchId(), e);
throw new BatchTransferException("批量转账处理失败", e);
}
}
/**
* 事务补偿机制
*/
@EventListener
public void handleTransactionCompensation(TransactionCompensationEvent event) {
log.info("开始事务补偿: transactionId={}, reason={}",
event.getTransactionId(), event.getReason());
try {
// 1. 查询原交易
BankingTransaction originalTx = transactionRepository.findByTransactionId(event.getTransactionId());
if (originalTx == null) {
log.warn("原交易不存在,无法补偿: transactionId={}", event.getTransactionId());
return;
}
// 2. 执行补偿操作
if (originalTx.getTransactionType() == TransactionType.TRANSFER) {
// 执行反向转账
TransferRequest compensationRequest = TransferRequest.builder()
.fromAccount(originalTx.getToAccount())
.toAccount(originalTx.getFromAccount())
.amount(originalTx.getAmount())
.currency(originalTx.getCurrency())
.description("交易补偿: " + event.getReason())
.build();
BankingTransactionResult result = processCoreTransfer(compensationRequest);
if (result.isSuccess()) {
log.info("事务补偿成功: originalTx={}, compensationTx={}",
event.getTransactionId(), result.getTransactionId());
} else {
log.error("事务补偿失败: originalTx={}", event.getTransactionId());
alertService.sendCompensationFailureAlert(event.getTransactionId(), result.getErrorMessage());
}
}
} catch (Exception e) {
log.error("事务补偿异常: transactionId={}", event.getTransactionId(), e);
alertService.sendCompensationExceptionAlert(event.getTransactionId(), e);
}
}
}
2. 电商订单系统事务设计
// 电商订单系统事务处理
@Service
public class EcommerceOrderTransactionService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private InventoryRepository inventoryRepository;
@Autowired
private PaymentRepository paymentRepository;
/**
* 订单创建事务:涉及多个业务环节
*/
@Transactional(
isolation = Isolation.READ_COMMITTED,
propagation = Propagation.REQUIRED,
timeout = 60,
rollbackFor = {OrderException.class, InventoryException.class, PaymentException.class}
)
public OrderCreationResult createOrderTransaction(CreateOrderRequest request) {
String orderNo = generateOrderNo();
log.info("开始订单创建事务: orderNo={}, userId={}", orderNo, request.getUserId());
try {
// 1. 参数验证
validateOrderRequest(request);
// 2. 库存预检(悲观锁)
Map<Long, ProductInventory> lockedInventories = lockAndCheckInventory(request.getItems());
// 3. 价格计算
PriceCalculationResult priceResult = calculateOrderPrice(request);
// 4. 创建订单
Order order = Order.builder()
.orderNo(orderNo)
.userId(request.getUserId())
.items(convertToOrderItems(request.getItems()))
.originalAmount(priceResult.getOriginalAmount())
.discountAmount(priceResult.getDiscountAmount())
.finalAmount(priceResult.getFinalAmount())
.status(OrderStatus.PENDING_PAYMENT)
.createTime(LocalDateTime.now())
.build();
order = orderRepository.save(order);
// 5. 扣减库存
deductInventory(lockedInventories, order.getItems());
// 6. 应用优惠券
if (request.getCouponIds() != null && !request.getCouponIds().isEmpty()) {
applyCoupons(order, request.getCouponIds());
}
// 7. 使用积分
if (request.getPointsToUse() != null && request.getPointsToUse() > 0) {
usePoints(order, request.getPointsToUse());
}
// 8. 记录订单创建日志
recordOrderCreationLog(order);
// 9. 发送订单创建事件(用于后续异步处理)
publishOrderCreatedEvent(order);
log.info("订单创建事务成功: orderNo={}, amount={}", orderNo, order.getFinalAmount());
return OrderCreationResult.success(orderNo, order.getFinalAmount());
} catch (OrderException | InventoryException | PaymentException e) {
log.error("订单创建业务异常: orderNo={}, error={}", orderNo, e.getMessage());
throw e;
} catch (Exception e) {
log.error("订单创建系统异常: orderNo={}", orderNo, e);
throw new OrderCreationException("订单创建失败", e);
}
}
/**
* 订单支付事务
*/
@Transactional
public PaymentResult processOrderPayment(PaymentRequest request) {
log.info("开始订单支付事务: orderNo={}, amount={}", request.getOrderNo(), request.getAmount());
try {
// 1. 获取订单(加锁)
Order order = orderRepository.findByOrderNoForUpdate(request.getOrderNo());
if (order == null) {
throw new OrderNotFoundException("订单不存在: " + request.getOrderNo());
}
// 2. 验证订单状态
if (order.getStatus() != OrderStatus.PENDING_PAYMENT) {
throw new InvalidOrderStatusException("订单状态不正确: " + order.getStatus());
}
// 3. 验证支付金额
if (!order.getFinalAmount().equals(request.getAmount())) {
throw new PaymentAmountMismatchException(
String.format("支付金额不匹配: expected=%s, actual=%s",
order.getFinalAmount(), request.getAmount())
);
}
// 4. 创建支付记录
Payment payment = Payment.builder()
.paymentNo(generatePaymentNo())
.orderNo(order.getOrderNo())
.userId(order.getUserId())
.amount(request.getAmount())
.paymentMethod(request.getPaymentMethod())
.status(PaymentStatus.PROCESSING)
.createTime(LocalDateTime.now())
.build();
payment = paymentRepository.save(payment);
// 5. 调用支付网关
GatewayPaymentResult gatewayResult = callPaymentGateway(request);
// 6. 更新支付状态
if (gatewayResult.isSuccess()) {
payment.setStatus(PaymentStatus.SUCCESS);
payment.setGatewayTransactionId(gatewayResult.getTransactionId());
payment.setPaymentTime(LocalDateTime.now());
paymentRepository.update(payment);
// 7. 更新订单状态
updateOrderStatusAfterPayment(order, PaymentStatus.SUCCESS);
// 8. 确认库存扣减
confirmInventoryDeduction(order);
// 9. 发送支付成功通知
sendPaymentSuccessNotification(order, payment);
log.info("订单支付成功: orderNo={}, paymentNo={}", order.getOrderNo(), payment.getPaymentNo());
return PaymentResult.success(payment.getPaymentNo());
} else {
// 支付失败
payment.setStatus(PaymentStatus.FAILED);
payment.setErrorMessage(gatewayResult.getErrorMessage());
paymentRepository.update(payment);
// 回滚库存
rollbackInventoryDeduction(order);
// 恢复优惠券和积分
restoreCouponsAndPoints(order);
// 更新订单状态
updateOrderStatusAfterPayment(order, PaymentStatus.FAILED);
log.warn("订单支付失败: orderNo={}, error={}", order.getOrderNo(), gatewayResult.getErrorMessage());
return PaymentResult.failed(gatewayResult.getErrorMessage());
}
} catch (PaymentException e) {
log.error("支付业务异常: orderNo={}, error={}", request.getOrderNo(), e.getMessage());
throw e;
} catch (Exception e) {
log.error("订单支付系统异常: orderNo={}", request.getOrderNo(), e);
throw new PaymentProcessingException("支付处理失败", e);
}
}
/**
* 订单取消事务
*/
@Transactional
public OrderCancellationResult cancelOrder(CancelOrderRequest request) {
log.info("开始订单取消事务: orderNo={}, reason={}", request.getOrderNo(), request.getReason());
try {
// 1. 获取订单(加锁)
Order order = orderRepository.findByOrderNoForUpdate(request.getOrderNo());
if (order == null) {
throw new OrderNotFoundException("订单不存在: " + request.getOrderNo());
}
// 2. 验证订单状态
if (!isOrderCancellable(order.getStatus())) {
throw new InvalidOrderStatusException(
String.format("订单当前状态不允许取消: status=%s", order.getStatus())
);
}
// 3. 处理退款(如果已支付)
if (order.getStatus() == OrderStatus.PAID || order.getStatus() == OrderStatus.SHIPPED) {
processOrderRefund(order);
}
// 4. 恢复库存
restoreInventory(order);
// 5. 恢复优惠券
if (order.getUsedCoupons() != null) {
restoreUsedCoupons(order);
}
// 6. 恢复积分
if (order.getUsedPoints() > 0) {
restoreUsedPoints(order);
}
// 7. 更新订单状态
order.setStatus(OrderStatus.CANCELLED);
order.setCancelTime(LocalDateTime.now());
order.setCancelReason(request.getReason());
order.setCancelledBy(request.getCancelledBy());
orderRepository.update(order);
// 8. 记录取消日志
recordOrderCancellationLog(order, request);
// 9. 发送订单取消通知
sendOrderCancellationNotification(order);
log.info("订单取消事务成功: orderNo={}", request.getOrderNo());
return OrderCancellationResult.success(request.getOrderNo());
} catch (OrderException e) {
log.error("订单取消业务异常: orderNo={}, error={}", request.getOrderNo(), e.getMessage());
throw e;
} catch (Exception e) {
log.error("订单取消系统异常: orderNo={}", request.getOrderNo(), e);
throw new OrderCancellationException("订单取消失败", e);
}
}
}
3. 库存管理系统事务设计
// 库存管理系统事务处理
@Service
public class InventoryTransactionService {
@Autowired
private InventoryRepository inventoryRepository;
@Autowired
private InventoryTransactionRepository transactionRepository;
/**
* 库存扣减事务:高并发场景
*/
@Transactional(
isolation = Isolation.READ_COMMITTED,
propagation = Propagation.REQUIRED,
timeout = 10,
rollbackFor = {InventoryException.class}
)
public InventoryDeductionResult deductInventory(DeductInventoryRequest request) {
log.info("开始库存扣减事务: productId={}, quantity={}, orderId={}",
request.getProductId(), request.getQuantity(), request.getOrderId());
try {
// 1. 获取库存信息(加锁)
ProductInventory inventory = inventoryRepository.findByProductIdForUpdate(request.getProductId());
if (inventory == null) {
throw new ProductNotFoundException("商品不存在: " + request.getProductId());
}
// 2. 验证库存充足性
if (inventory.getAvailableQuantity() < request.getQuantity()) {
throw new InsufficientInventoryException(
String.format("库存不足: productId=%s, available=%s, required=%s",
request.getProductId(), inventory.getAvailableQuantity(), request.getQuantity())
);
}
// 3. 检查库存状态
if (inventory.getStatus() != InventoryStatus.AVAILABLE) {
throw new InventoryStatusException("库存状态异常: " + inventory.getStatus());
}
// 4. 执行库存扣减
int updatedRows = inventoryRepository.deductInventory(
request.getProductId(),
request.getQuantity(),
inventory.getVersion()
);
if (updatedRows == 0) {
throw new ConcurrentModificationException("库存并发修改,请重试");
}
// 5. 记录库存变动
InventoryTransaction transaction = InventoryTransaction.builder()
.transactionId(generateTransactionId())
.productId(request.getProductId())
.quantityChange(-request.getQuantity())
.transactionType(InventoryTransactionType.ORDER_DEDUCTION)
.orderId(request.getOrderId())
.beforeQuantity(inventory.getAvailableQuantity())
.afterQuantity(inventory.getAvailableQuantity() - request.getQuantity())
.createTime(LocalDateTime.now())
.build();
transactionRepository.save(transaction);
// 6. 更新库存统计
updateInventoryStatistics(inventory, request.getQuantity());
log.info("库存扣减事务成功: productId={}, quantity={}, transactionId={}",
request.getProductId(), request.getQuantity(), transaction.getTransactionId());
return InventoryDeductionResult.success(
transaction.getTransactionId(),
inventory.getAvailableQuantity() - request.getQuantity()
);
} catch (InventoryException e) {
log.error("库存业务异常: productId={}, error={}", request.getProductId(), e.getMessage());
throw e;
} catch (Exception e) {
log.error("库存扣减系统异常: productId={}", request.getProductId(), e);
throw new InventoryDeductionException("库存扣减失败", e);
}
}
/**
* 批量库存扣减:秒杀场景
*/
@Transactional
public BatchDeductionResult batchDeductInventory(BatchDeductionRequest request) {
log.info("开始批量库存扣减: productId={}, totalQuantity={}, orderCount={}",
request.getProductId(), request.getTotalQuantity(), request.getOrders().size());
try {
// 1. 获取商品库存(加锁)
ProductInventory inventory = inventoryRepository.findByProductIdForUpdate(request.getProductId());
// 2. 验证总库存
if (inventory.getAvailableQuantity() < request.getTotalQuantity()) {
throw new InsufficientInventoryException("总库存不足");
}
// 3. 创建批量扣减任务
BatchDeductionTask task = BatchDeductionTask.builder()
.taskId(generateTaskId())
.productId(request.getProductId())
.totalQuantity(request.getTotalQuantity())
.orderCount(request.getOrders().size())
.status(BatchStatus.PROCESSING)
.createTime(LocalDateTime.now())
.build();
task = inventoryRepository.saveBatchTask(task);
// 4. 批量扣减库存
int deductedQuantity = 0;
List<InventoryTransaction> transactions = new ArrayList<>();
for (OrderInventory order : request.getOrders()) {
// 扣减单个订单库存
int updatedRows = inventoryRepository.deductInventory(
request.getProductId(),
order.getQuantity(),
inventory.getVersion()
);
if (updatedRows > 0) {
deductedQuantity += order.getQuantity();
// 记录交易
InventoryTransaction transaction = InventoryTransaction.builder()
.transactionId(generateTransactionId())
.productId(request.getProductId())
.quantityChange(-order.getQuantity())
.transactionType(InventoryTransactionType.BATCH_DEDUCTION)
.orderId(order.getOrderId())
.batchTaskId(task.getTaskId())
.createTime(LocalDateTime.now())
.build();
transactions.add(transaction);
}
}
// 5. 批量保存交易记录
if (!transactions.isEmpty()) {
transactionRepository.batchSave(transactions);
}
// 6. 更新批量任务状态
task.setProcessedQuantity(deductedQuantity);
task.setSuccessCount(transactions.size());
task.setStatus(deductedQuantity == request.getTotalQuantity() ? BatchStatus.SUCCESS : BatchStatus.PARTIAL_SUCCESS);
task.setCompleteTime(LocalDateTime.now());
inventoryRepository.updateBatchTask(task);
log.info("批量库存扣减完成: taskId={}, deducted={}, total={}",
task.getTaskId(), deductedQuantity, request.getTotalQuantity());
return BatchDeductionResult.success(task.getTaskId(), deductedQuantity);
} catch (Exception e) {
log.error("批量库存扣减异常", e);
throw new BatchDeductionException("批量库存扣减失败", e);
}
}
/**
* 库存回滚事务
*/
@Transactional
public InventoryRollbackResult rollbackInventory(InventoryRollbackRequest request) {
log.info("开始库存回滚事务: transactionId={}, productId={}, quantity={}",
request.getOriginalTransactionId(), request.getProductId(), request.getQuantity());
try {
// 1. 查询原交易
InventoryTransaction originalTx = transactionRepository.findByTransactionId(request.getOriginalTransactionId());
if (originalTx == null) {
throw new TransactionNotFoundException("原交易不存在: " + request.getOriginalTransactionId());
}
// 2. 验证回滚条件
if (originalTx.getTransactionType() != InventoryTransactionType.ORDER_DEDUCTION) {
throw new InvalidRollbackException("该交易类型不支持回滚: " + originalTx.getTransactionType());
}
if (originalTx.getRollbackStatus() == RollbackStatus.ROLLED_BACK) {
log.warn("交易已回滚,跳过: transactionId={}", request.getOriginalTransactionId());
return InventoryRollbackResult.skipped("交易已回滚");
}
// 3. 获取库存信息(加锁)
ProductInventory inventory = inventoryRepository.findByProductIdForUpdate(request.getProductId());
// 4. 执行库存回滚
int updatedRows = inventoryRepository.increaseInventory(
request.getProductId(),
request.getQuantity(),
inventory.getVersion()
);
if (updatedRows == 0) {
throw new ConcurrentModificationException("库存并发修改,请重试");
}
// 5. 记录回滚交易
InventoryTransaction rollbackTx = InventoryTransaction.builder()
.transactionId(generateTransactionId())
.productId(request.getProductId())
.quantityChange(request.getQuantity())
.transactionType(InventoryTransactionType.ROLLBACK)
.orderId(originalTx.getOrderId())
.relatedTransactionId(originalTx.getTransactionId())
.beforeQuantity(inventory.getAvailableQuantity())
.afterQuantity(inventory.getAvailableQuantity() + request.getQuantity())
.createTime(LocalDateTime.now())
.build();
transactionRepository.save(rollbackTx);
// 6. 更新原交易回滚状态
originalTx.setRollbackStatus(RollbackStatus.ROLLED_BACK);
originalTx.setRollbackTime(LocalDateTime.now());
originalTx.setRollbackReason(request.getReason());
transactionRepository.update(originalTx);
// 7. 更新库存统计
updateInventoryStatisticsAfterRollback(inventory, request.getQuantity());
log.info("库存回滚事务成功: rollbackTx={}, originalTx={}",
rollbackTx.getTransactionId(), originalTx.getTransactionId());
return InventoryRollbackResult.success(rollbackTx.getTransactionId());
} catch (InventoryException e) {
log.error("库存回滚业务异常: transactionId={}, error={}",
request.getOriginalTransactionId(), e.getMessage());
throw e;
} catch (Exception e) {
log.error("库存回滚系统异常: transactionId={}", request.getOriginalTransactionId(), e);
throw new InventoryRollbackException("库存回滚失败", e);
}
}
}
事务性数据存储架构演进路径
总结
事务性数据存储架构法则是构建可靠业务系统的核心原则。通过使用RDBMS/SQL数据库的完整事务机制,我们能够:
核心原则
- 强一致性保证:通过ACID特性确保数据的完整性和一致性
- 隔离级别选择:根据业务场景选择合适的事务隔离级别
- 异常处理机制:建立完善的事务异常处理和补偿机制
- 并发控制:通过锁机制和MVCC实现高效的并发控制
169万+

被折叠的 条评论
为什么被折叠?



