
在分布式系统和复杂业务场景中,事务管理是保证数据一致性的核心环节。想象这样一个场景:用户下单时,系统需要扣减库存、创建订单、扣减余额,这三个操作必须同时成功或同时失败。但如果这三个操作分别位于不同的服务或方法中,如何确保它们处于同一个事务中?
这就是 Spring 事务传播机制要解决的问题。它像一只 "隐形之手",在方法调用之间协调事务的创建、加入和结束,确保数据操作的一致性。理解 Spring 事务传播机制,不仅能帮助你避免常见的事务问题,还能让你在复杂业务场景中设计出更健壮的系统。
本文将从基础概念到实战案例,全面解析 Spring 的 7 种事务传播行为,带你彻底掌握这一核心技术。
事务(Transaction)是数据库操作的基本单元,它是一系列操作的集合,这些操作要么全部成功,要么全部失败,不存在部分成功的情况。
事务具有 ACID 特性:
当一个事务方法调用另一个事务方法时,Spring 需要决定如何处理这两个方法的事务关系:是使用同一个事务,还是创建新的事务?事务传播机制(Transaction Propagation)就是定义这种处理规则的机制。

事务传播机制解决的核心问题是:当多个事务方法嵌套调用时,如何管理事务的边界和行为。
Spring 在Propagation枚举类中定义了 7 种事务传播行为:
public enum Propagation {
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
NEVER(TransactionDefinition.PROPAGATION_NEVER),
NESTED(TransactionDefinition.PROPAGATION_NESTED);
private final int value;
Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
这些传播行为定义了内部方法如何与外部方法的事务进行交互,是 Spring 事务管理的核心。
要理解事务传播机制,首先需要了解 Spring 是如何管理事务的。

当一个标注了@Transactional的方法被调用时,Spring 会通过 AOP 拦截该方法,执行以下步骤:

事务传播机制的核心逻辑就在步骤 D 中,Spring 会根据当前是否存在事务以及指定的传播行为,决定如何处理事务。
Spring 通过ThreadLocal将事务与当前线程绑定,实现事务的传播:
// 简化版的事务绑定逻辑
public class TransactionSynchronizationManager {
// 存储当前线程的事务连接
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
// 存储当前线程的事务状态
private static final ThreadLocal<TransactionStatus> transactionStatus =
new NamedThreadLocal<>("Current transaction status");
// 绑定资源到当前线程
public static void bindResource(Object key, Object value) {
Map<Object, Object> map = resources.get();
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
map.put(key, value);
}
// 从当前线程获取资源
public static Object getResource(Object key) {
Map<Object, Object> map = resources.get();
return (map != null ? map.get(key) : null);
}
// 从当前线程解绑资源
public static Object unbindResource(Object key) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
return map.remove(key);
}
}
当方法调用时,Spring 会检查当前线程是否已绑定事务资源:
这种线程绑定机制是事务传播的基础,使得嵌套调用的方法能够感知到外部方法的事务。
Spring 定义了 7 种事务传播行为,每种行为都有其特定的使用场景和行为规则。
行为定义:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

适用场景:大多数业务场景,这是 Spring 的默认传播行为。
示例代码:
/**
* 订单服务
* @author ken
*/
@Service
@Slf4j
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private InventoryService inventoryService;
/**
* 创建订单(无事务)
*/
public void createOrderWithoutTx(Order order) {
log.info("创建订单: {}", order);
orderMapper.insert(order);
// 调用扣减库存方法(REQUIRED)
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
}
/**
* 创建订单(有事务)
*/
@Transactional(propagation = Propagation.REQUIRED)
public void createOrderWithTx(Order order) {
log.info("创建订单: {}", order);
orderMapper.insert(order);
// 调用扣减库存方法(REQUIRED)
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
}
}
/**
* 库存服务
* @author ken
*/
@Service
@Slf4j
public class InventoryService {
@Autowired
private InventoryMapper inventoryMapper;
/**
* 扣减库存
*/
@Transactional(propagation = Propagation.REQUIRED)
public void reduceStock(Long productId, Integer quantity) {
log.info("扣减库存, 商品ID: {}, 数量: {}", productId, quantity);
Inventory inventory = inventoryMapper.selectById(productId);
if (inventory.getStock() < quantity) {
throw new InsufficientStockException("库存不足");
}
inventory.setStock(inventory.getStock() - quantity);
inventoryMapper.updateById(inventory);
}
}
执行结果分析:
createOrderWithoutTx():reduceStock()会创建新事务createOrderWithTx():reduceStock()加入外部事务行为定义:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式运行。

适用场景:适用于那些 "可选事务" 的方法,这些方法在有事务时就参与事务,没有事务时也能正常运行。例如查询操作,通常不需要事务,但如果已经在事务中执行,也可以参与事务。
示例代码:
/**
* 统计服务
* @author ken
*/
@Service
@Slf4j
public class StatisticsService {
@Autowired
private StatisticsMapper statisticsMapper;
/**
* 更新统计数据
* 支持事务,但不强制要求
*/
@Transactional(propagation = Propagation.SUPPORTS)
public void updateStatistics(Long productId) {
log.info("更新商品统计数据, 商品ID: {}", productId);
Statistics stats = statisticsMapper.selectById(productId);
if (stats == null) {
stats = new Statistics();
stats.setProductId(productId);
stats.setSaleCount(1);
statisticsMapper.insert(stats);
} else {
stats.setSaleCount(stats.getSaleCount() + 1);
statisticsMapper.updateById(stats);
}
}
}
// 在OrderService中添加调用
@Service
@Slf4j
public class OrderService {
// ... 其他代码省略 ...
/**
* 创建订单(有事务)
*/
@Transactional(propagation = Propagation.REQUIRED)
public void createOrderWithTx(Order order) {
log.info("创建订单: {}", order);
orderMapper.insert(order);
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
// 调用统计服务(SUPPORTS)
statisticsService.updateStatistics(order.getProductId());
}
/**
* 查询订单(无事务)
*/
public Order queryOrder(Long orderId) {
Order order = orderMapper.selectById(orderId);
// 调用统计服务(SUPPORTS)
statisticsService.updateStatistics(order.getProductId());
return order;
}
}
执行结果分析:
createOrderWithTx()中调用updateStatistics():queryOrder()中调用updateStatistics():行为定义:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

适用场景:适用于那些必须在事务中执行的操作,确保这些操作不会在无事务的环境中执行。例如关键的金融操作,必须在事务保护下执行。
示例代码:
/**
* 支付服务
* @author ken
*/
@Service
@Slf4j
public class PaymentService {
@Autowired
private PaymentMapper paymentMapper;
/**
* 记录支付信息
* 必须在事务中运行
*/
@Transactional(propagation = Propagation.MANDATORY)
public void recordPayment(Payment payment) {
log.info("记录支付信息: {}", payment);
paymentMapper.insert(payment);
}
}
// 在OrderService中添加调用
@Service
@Slf4j
public class OrderService {
// ... 其他代码省略 ...
/**
* 创建订单并支付(有事务)
*/
@Transactional(propagation = Propagation.REQUIRED)
public void createOrderAndPay(Order order, Payment payment) {
log.info("创建订单并支付");
orderMapper.insert(order);
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
// 调用支付服务(MANDATORY)
paymentService.recordPayment(payment);
}
/**
* 创建订单并支付(无事务)
*/
public void createOrderAndPayWithoutTx(Order order, Payment payment) {
log.info("创建订单并支付(无事务)");
orderMapper.insert(order);
// 调用支付服务(MANDATORY)
paymentService.recordPayment(payment);
}
}
执行结果分析:
createOrderAndPay():createOrderAndPayWithoutTx():IllegalTransactionStateException行为定义:无论当前是否存在事务,都创建一个新的事务。如果当前存在事务,则将当前事务挂起。

适用场景:适用于那些需要独立事务的操作,这些操作无论外部事务成功与否都应该被提交。例如日志记录、操作审计等,即使主业务失败,这些记录也需要保留。
示例代码:
/**
* 日志服务
* @author ken
*/
@Service
@Slf4j
public class LogService {
@Autowired
private OperationLogMapper logMapper;
/**
* 记录操作日志
* 使用独立事务
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void recordLog(OperationLog log) {
log.info("记录操作日志: {}", log);
logMapper.insert(log);
}
}
// 在OrderService中添加调用
@Service
@Slf4j
public class OrderService {
// ... 其他代码省略 ...
/**
* 创建订单(有事务)
*/
@Transactional(propagation = Propagation.REQUIRED)
public void createOrderWithLog(Order order) {
log.info("创建订单: {}", order);
// 记录操作日志(REQUIRES_NEW)
OperationLog log = new OperationLog();
log.setOperation("CREATE_ORDER");
log.setContent(JSON.toJSONString(order));
logService.recordLog(log);
orderMapper.insert(order);
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
// 模拟业务异常
if (order.getAmount() < 0) {
throw new IllegalArgumentException("订单金额不能为负数");
}
}
}
执行结果分析:
行为定义:以非事务方式运行。如果当前存在事务,则将当前事务挂起。

适用场景:适用于那些不需要事务的操作,即使外部存在事务,也以非事务方式运行。例如一些耗时的查询操作,不需要事务支持,可以提高性能。
示例代码:
/**
* 报表服务
* @author ken
*/
@Service
@Slf4j
public class ReportService {
@Autowired
private ReportMapper reportMapper;
/**
* 生成销售报表
* 不需要事务支持
*/
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public Report generateSalesReport(LocalDate startDate, LocalDate endDate) {
log.info("生成销售报表, 开始日期: {}, 结束日期: {}", startDate, endDate);
// 模拟耗时的报表生成过程
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("报表生成被中断");
}
Report report = new Report();
report.setStartDate(startDate);
report.setEndDate(endDate);
report.setContent("销售报表内容...");
reportMapper.insert(report);
return report;
}
}
// 在OrderService中添加调用
@Service
@Slf4j
public class OrderService {
// ... 其他代码省略 ...
/**
* 创建订单并生成报表
*/
@Transactional(propagation = Propagation.REQUIRED)
public void createOrderAndGenerateReport(Order order) {
log.info("创建订单并生成报表");
orderMapper.insert(order);
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
// 调用报表服务(NOT_SUPPORTED)
reportService.generateSalesReport(LocalDate.now().minusDays(7), LocalDate.now());
// 模拟异常
if (order.getQuantity() > 100) {
throw new IllegalArgumentException("订单数量过大");
}
}
}
执行结果分析:
行为定义:以非事务方式运行。如果当前存在事务,则抛出异常。

适用场景:适用于那些绝对不能在事务中运行的操作。例如某些特定的统计或日志操作,如果在事务中运行可能会导致性能问题或数据不一致。
示例代码:
/**
* 审计服务
* @author ken
*/
@Service
@Slf4j
public class AuditService {
@Autowired
private AuditLogMapper auditLogMapper;
/**
* 记录审计日志
* 不允许在事务中运行
*/
@Transactional(propagation = Propagation.NEVER)
public void recordAuditLog(AuditLog log) {
log.info("记录审计日志: {}", log);
auditLogMapper.insert(log);
}
}
// 在OrderService中添加调用
@Service
@Slf4j
public class OrderService {
// ... 其他代码省略 ...
/**
* 创建订单并记录审计日志(有事务)
*/
@Transactional(propagation = Propagation.REQUIRED)
public void createOrderWithAudit(Order order) {
log.info("创建订单并记录审计日志");
orderMapper.insert(order);
// 调用审计服务(NEVER)
AuditLog log = new AuditLog();
log.setOperation("CREATE_ORDER");
log.setOperator("system");
auditService.recordAuditLog(log);
}
/**
* 创建订单并记录审计日志(无事务)
*/
public void createOrderWithAuditWithoutTx(Order order) {
log.info("创建订单并记录审计日志(无事务)");
orderMapper.insert(order);
// 调用审计服务(NEVER)
AuditLog log = new AuditLog();
log.setOperation("CREATE_ORDER");
log.setOperator("system");
auditService.recordAuditLog(log);
}
}
执行结果分析:
createOrderWithAudit():IllegalTransactionStateExceptioncreateOrderWithAuditWithoutTx():行为定义:如果当前存在事务,则创建一个嵌套事务(子事务),嵌套在当前事务中;如果当前没有事务,则创建一个新的事务。
嵌套事务与外部事务的关系:

适用场景:适用于那些需要部分回滚能力的场景。例如复杂的订单处理,其中某些步骤失败可以回滚该步骤,但不影响其他步骤的继续执行。
示例代码:
/**
* 积分服务
* @author ken
*/
@Service
@Slf4j
public class PointsService {
@Autowired
private PointsMapper pointsMapper;
/**
* 增加用户积分
* 使用嵌套事务
*/
@Transactional(propagation = Propagation.NESTED)
public void addPoints(Long userId, Integer points) {
log.info("增加用户积分, 用户ID: {}, 积分: {}", userId, points);
PointsAccount account = pointsMapper.selectById(userId);
if (account == null) {
account = new PointsAccount();
account.setUserId(userId);
account.setPoints(points);
pointsMapper.insert(account);
} else {
account.setPoints(account.getPoints() + points);
pointsMapper.updateById(account);
}
// 模拟积分操作失败
if (points < 0) {
throw new IllegalArgumentException("积分不能为负数");
}
}
}
// 在OrderService中添加调用
@Service
@Slf4j
public class OrderService {
// ... 其他代码省略 ...
/**
* 创建订单并增加积分
*/
@Transactional(propagation = Propagation.REQUIRED)
public void createOrderAndAddPoints(Order order) {
log.info("创建订单并增加积分");
orderMapper.insert(order);
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
try {
// 调用积分服务(NESTED)
pointsService.addPoints(order.getUserId(), order.getAmount().intValue() / 10);
} catch (IllegalArgumentException e) {
log.error("积分操作失败, 继续执行订单流程: {}", e.getMessage());
// 捕获子事务异常, 外部事务继续执行
}
// 模拟外部事务是否回滚
if (order.getAmount() > 10000) {
throw new IllegalArgumentException("订单金额过大, 需要人工审核");
}
}
}
执行结果分析:
NESTED 与 REQUIRES_NEW 的区别:
假设一个完整的订单创建流程包括以下步骤:
我们需要设计合理的事务传播机制,确保数据一致性的同时,满足业务需求。
/**
* 订单流程服务
* 协调订单创建的完整流程
* @author ken
*/
@Service
@Slf4j
public class OrderProcessService {
@Autowired
private OrderService orderService;
@Autowired
private InventoryService inventoryService;
@Autowired
private AccountService accountService;
@Autowired
private PointsService pointsService;
@Autowired
private LogService logService;
/**
* 完整的订单创建流程
*/
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public Order createCompleteOrder(OrderCreateDTO dto) {
log.info("开始处理订单创建流程: {}", dto);
// 1. 创建订单记录 - 参与主事务
Order order = new Order();
order.setUserId(dto.getUserId());
order.setProductId(dto.getProductId());
order.setQuantity(dto.getQuantity());
order.setAmount(dto.getAmount());
order.setStatus(OrderStatus.PENDING);
orderService.createOrder(order);
try {
// 2. 扣减商品库存 - 参与主事务
inventoryService.reduceStock(dto.getProductId(), dto.getQuantity());
// 3. 扣减用户余额 - 参与主事务
accountService.reduceBalance(dto.getUserId(), dto.getAmount());
// 4. 增加用户积分 - 嵌套事务,失败不影响主流程
pointsService.addPoints(dto.getUserId(), dto.getAmount().intValue() / 10);
} catch (InsufficientStockException | InsufficientBalanceException e) {
log.error("订单创建失败: {}", e.getMessage());
// 库存或余额不足,回滚整个事务
throw e;
} catch (Exception e) {
log.error("非关键步骤失败: {}", e.getMessage());
// 非关键步骤失败,记录日志,继续执行
}
// 5. 记录操作日志 - 独立事务,必须成功
OperationLog log = new OperationLog();
log.setOperation("CREATE_ORDER");
log.setContent(JSON.toJSONString(order));
logService.recordLog(log);
// 6. 更新订单状态为成功
order.setStatus(OrderStatus.SUCCESS);
orderService.updateOrder(order);
log.info("订单创建流程完成, 订单ID: {}", order.getId());
return order;
}
}
/**
* 账户服务
* @author ken
*/
@Service
@Slf4j
public class AccountService {
@Autowired
private AccountMapper accountMapper;
/**
* 扣减用户余额
*/
@Transactional(propagation = Propagation.REQUIRED)
public void reduceBalance(Long userId, BigDecimal amount) {
log.info("扣减用户余额, 用户ID: {}, 金额: {}", userId, amount);
Account account = accountMapper.selectById(userId);
if (account.getBalance().compareTo(amount) < 0) {
throw new InsufficientBalanceException("余额不足");
}
account.setBalance(account.getBalance().subtract(amount));
accountMapper.updateById(account);
}
}
各服务的事务传播配置:
OrderProcessService.createCompleteOrder():REQUIRED - 主事务OrderService.createOrder():REQUIRED - 参与主事务InventoryService.reduceStock():REQUIRED - 参与主事务AccountService.reduceBalance():REQUIRED - 参与主事务PointsService.addPoints():NESTED - 嵌套事务,失败可回滚但不影响主流程LogService.recordLog():REQUIRES_NEW - 独立事务,确保日志被记录这种配置的优势:
在分布式系统中,多个服务之间的事务协调更为复杂。虽然 Spring 的事务传播机制主要针对单库事务,但可以与分布式事务解决方案结合使用。
/**
* 分布式订单服务
* 协调多个微服务完成订单创建
* @author ken
*/
@Service
@Slf4j
public class DistributedOrderService {
@Autowired
private LocalOrderService localOrderService;
@Autowired
private RemoteInventoryService remoteInventoryService;
@Autowired
private RemotePaymentService remotePaymentService;
@Autowired
private RemoteNotificationService remoteNotificationService;
/**
* 创建分布式订单
* 使用Seata分布式事务协调
*/
@GlobalTransactional(rollbackFor = Exception.class) // Seata分布式事务注解
public OrderDTO createDistributedOrder(OrderCreateDTO dto) {
log.info("开始创建分布式订单: {}", dto);
// 1. 创建本地订单
OrderDTO order = localOrderService.createOrder(dto);
try {
// 2. 远程调用库存服务扣减库存
remoteInventoryService.reduceStock(dto.getProductId(), dto.getQuantity());
// 3. 远程调用支付服务处理支付
PaymentResult result = remotePaymentService.processPayment(
dto.getUserId(), order.getOrderId(), dto.getAmount());
if (result.isSuccess()) {
// 4. 更新订单状态为已支付
localOrderService.updateOrderStatus(order.getOrderId(), OrderStatus.PAID);
// 5. 远程调用通知服务发送消息(非关键步骤)
try {
remoteNotificationService.sendPaymentSuccessNotification(
dto.getUserId(), order.getOrderId());
} catch (Exception e) {
log.error("发送通知失败, 已记录但不影响主流程: {}", e.getMessage());
}
} else {
throw new PaymentFailedException("支付失败: " + result.getErrorMessage());
}
} catch (Exception e) {
log.error("分布式订单处理失败: {}", e.getMessage());
// 抛出异常,触发全局回滚
throw e;
}
log.info("分布式订单创建完成: {}", order.getOrderId());
return order;
}
}
/**
* 本地订单服务
* @author ken
*/
@Service
@Slf4j
public class LocalOrderService {
@Autowired
private OrderMapper orderMapper;
/**
* 创建本地订单
*/
@Transactional(propagation = Propagation.REQUIRED)
public OrderDTO createOrder(OrderCreateDTO dto) {
log.info("创建本地订单: {}", dto);
// 订单创建逻辑...
}
/**
* 更新订单状态
*/
@Transactional(propagation = Propagation.REQUIRED)
public void updateOrderStatus(Long orderId, OrderStatus status) {
log.info("更新订单状态, 订单ID: {}, 状态: {}", orderId, status);
// 状态更新逻辑...
}
}
/**
* 远程库存服务客户端
* @author ken
*/
@FeignClient(name = "inventory-service")
public interface RemoteInventoryService {
/**
* 远程扣减库存
*/
@PostMapping("/api/inventory/reduce")
@Transactional(propagation = Propagation.MANDATORY) // 必须在分布式事务中运行
void reduceStock(@RequestParam("productId") Long productId,
@RequestParam("quantity") Integer quantity);
}
分布式场景下的事务传播策略:
@GlobalTransactional注解标记(以 Seata 为例)REQUIRED传播行为,参与全局事务MANDATORY传播行为,确保必须在全局事务中运行REQUIRES_NEW或捕获异常,避免影响主流程问题描述:当一个事务方法调用同一个类中的另一个事务方法时,事务传播机制失效。
@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder(Order order) {
// 业务逻辑...
// 调用同一个类中的另一个事务方法
this.updateOrderStatus(order.getId(), OrderStatus.PENDING);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateOrderStatus(Long orderId, OrderStatus status) {
// 更新订单状态...
}
}
问题原因:Spring 事务通过 AOP 实现,自调用时不会经过 AOP 代理,因此事务注解失效。
解决方案:
@Service
public class OrderService {
// 注入自己的代理对象
@Autowired
private OrderService orderService;
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder(Order order) {
// 业务逻辑...
// 通过代理对象调用方法
orderService.updateOrderStatus(order.getId(), OrderStatus.PENDING);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateOrderStatus(Long orderId, OrderStatus status) {
// 更新订单状态...
}
}
问题描述:当事务方法中的异常被捕获后,事务不会回滚。
@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder(Order order) {
try {
orderMapper.insert(order);
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
} catch (Exception e) {
log.error("创建订单失败", e);
// 异常被捕获,没有重新抛出
}
}
}
问题原因:Spring 事务通过检测未被捕获的异常来触发回滚,如果异常被捕获,事务管理器会认为方法执行成功。
解决方案:捕获异常后重新抛出,或手动触发回滚。
@Service
public class OrderService {
@Autowired
private TransactionStatus transactionStatus;
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder(Order order) {
try {
orderMapper.insert(order);
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
} catch (Exception e) {
log.error("创建订单失败", e);
// 方案1: 重新抛出异常
throw new BusinessException("创建订单失败", e);
// 方案2: 手动回滚
// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
}
问题描述:抛出检查型异常时,事务不会回滚。
@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder(Order order) throws IOException {
orderMapper.insert(order);
// 抛出检查型异常
throw new IOException("文件操作失败");
}
}
问题原因:Spring 默认只对未检查异常(继承自RuntimeException)和Error进行回滚,对检查型异常不回滚。
解决方案:指定rollbackFor属性,明确需要回滚的异常类型。
@Service
public class OrderService {
// 指定需要回滚的异常类型
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void createOrder(Order order) throws IOException {
orderMapper.insert(order);
throw new IOException("文件操作失败");
}
}
问题描述:不同事务传播行为与隔离级别组合时可能产生意想不到的结果。
解决方案:了解不同传播行为对隔离级别的影响:
REQUIRED和MANDATORY:使用外部事务的隔离级别REQUIRES_NEW和NESTED:使用自己定义的隔离级别SUPPORTS:如果加入外部事务,使用外部事务的隔离级别NOT_SUPPORTED和NEVER:不使用事务,隔离级别无效建议:核心事务使用明确的隔离级别,非核心事务可以使用默认设置。
REQUIRED,它能保证相关操作在同一个事务中。REQUIRES_NEW。MANDATORY确保不会在无事务环境中执行。SUPPORTS可以提高灵活性。NESTED,但要注意数据库是否支持保存点。rollbackFor属性,明确哪些异常需要触发回滚。@Transactional(propagation = Propagation.REQUIRED, timeout = 30) // 超时时间30秒
public void processOrder(Order order) {
// 业务逻辑...
}
readOnly = true可以提高性能,特别是对于 Hibernate 等 ORM 框架。@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public List<Order> queryOrders(Long userId) {
// 查询逻辑...
}
Spring 事务传播机制是保证数据一致性的关键技术,它通过定义不同的传播行为,解决了嵌套方法调用中的事务管理问题。