在Spring Boot项目中,使用@Transactional(rollbackFor = Exception.class)
修饰的方法内设计异常处理时,需注意以下关键点:
1. 异常抛出机制
-
不要吞没异常:若方法内部通过
try-catch
捕获了异常但未重新抛出,事务将不会回滚。即使配置了rollbackFor = Exception.class
,Spring仍需感知到异常才能触发回滚。 -
正确示例:
@Transactional(rollbackFor = Exception.class) public void updateData() throws CustomException { try { // 业务逻辑 } catch (Exception e) { throw new CustomException("操作失败", e); // 抛出受检异常 } }
2. 嵌套事务处理
-
传播行为选择:若存在嵌套事务(如方法A调用方法B),需根据业务场景选择传播级别:
Propagation.REQUIRES_NEW
:内部事务独立提交/回滚,不影响外部事务。Propagation.NESTED
:内部事务通过保存点(Savepoint)实现局部回滚,外部事务提交时整体生效。
-
示例配置:
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) public void innerMethod() { ... }
3. 自调用问题
-
避免同类调用:若事务方法被同一类中的其他方法调用(非代理调用),事务注解会失效。解决方案:
- 将事务方法拆分到另一个Bean中。
- 使用
AopContext.currentProxy()
获取代理对象调用。
4. 全局异常处理
-
统一捕获异常:通过
@ControllerAdvice
和@ExceptionHandler
全局处理异常,避免事务方法内耦合异常响应逻辑。 -
示例:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception e) { // 记录日志并返回统一错误格式 return ResponseEntity.status(500).body(new ErrorResponse("系统异常")); } }
5. 手动回滚标记
-
强制回滚场景:若需在捕获异常后不抛出但仍需回滚,可手动标记事务状态:
@Transactional(rollbackFor = Exception.class) public void updateData() { try { // 业务逻辑 } catch (Exception e) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }
总结
- 核心原则:确保异常能被Spring事务管理器感知(抛出或手动标记回滚)。
- 传播级别:根据业务需求选择
REQUIRES_NEW
或NESTED
隔离嵌套事务。 - 代码结构:通过全局异常处理解耦事务与响应逻辑,避免自调用陷阱。