BusinessException抛出后逻辑未中断,通常因异常被try-catch吞没或未继承RuntimeException;Spring仅对未检查异常自动事务回滚和全局拦截,需确保其继承自RuntimeException、调用链无静默捕获、@ExceptionHandler明确声明且@Transactional配置rollbackFor。
throw BusinessException 时为什么逻辑没中断?
常见现象是写了
,但后续代码仍执行——多半因为抛出点被 try-catch 吞掉了,或者 BusinessExeption 没继承
。Spring 默认只对未检查异常(即继承
)做事务回滚和全局异常拦截,如果 BusinessException 是
的子类,
后虽能抛出,但可能被上层静默捕获,或事务不回滚。
实操建议:
确认
继承自
,而非
检查调用链中是否存在无意识的
,尤其在工具类或 AOP 切面里
若用 Spring Boot,确保
中的
明确声明了
在 Service 层 throw 的典型位置和参数设计
不是所有校验都适合 throw。重点放在「业务规则不可绕过」的节点:比如重复提交、状态非法变更、权限越界、余额不足。这时
不是报错,而是明确拒绝并终止流程。
实操建议:
避免在 DTO 转 VO 或简单字段判空时 throw,优先用
或 JSR-303 注解
构造
时传入可定位的错误码,如
不要在循环内频繁 throw,除非每次都是独立业务单元;否则考虑收集错误后统一抛出
throw 后事务不回滚?检查这三点
即使
成功,Service 方法加了
,事务也可能没回滚——这不是
的问题,而是传播机制或异常类型不匹配。
实操建议:
确认方法是 public,且被 Spring 容器管理(非 this.xxx() 直接调用)
检查
的
属性是否包含
,例如:
若 BusinessException 是 RuntimeException 子类,但仍有不回滚,可能是事务代理失效,用
并通过
调用
前端拿不到具体错误信息?别让 BusinessException 被二次包装
常见坑是全局异常处理器里把
包装成通用
,但错误码/消息被覆盖或转成了模糊提示(如“操作失败”),导致前端无法做差异化处理。
实操建议:
在
方法中,直接取
和自定义的
字段,不要 toString()
避免在 Controller 层再 catch BusinessException 做日志+rethrow,容易破坏异常原始堆栈和语义
如果 BusinessException 有分级(如警告级不中断流程),那就别 throw,改用返回值封装,
应代表「必须终止」
业务逻辑的「非法」不是靠 if-else 跑完才判断,而是用
在入口就卡住。最容易忽略的是异常类型继承关系和事务传播配置,这两处一错,
就变成无效的摆设。
throw new BusinessException("参数错误")RuntimeExceptionRuntimeExceptionExceptionthrowBusinessExceptionRuntimeExceptionExceptiontry { ... } catch (Exception e) { ... }@ControllerAdvice@ExceptionHandlerBusinessException.classthrowAssert.notNull()BusinessExceptionnew BusinessException("USER_STATUS_INVALID", "用户状态不允许执行此操作")throw@Transactionalthrow@TransactionalrollbackForBusinessException.class@Transactional(rollbackFor = BusinessException.class)@EnableAspectJAutoProxy(exposeProxy = true)AopContext.currentProxy()BusinessExceptionResult.fail()@ExceptionHandler(BusinessException.class)e.getMessage()getCode()throwthrowthrow