找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

686

积分

0

好友

88

主题
发表于 6 小时前 | 查看: 0| 回复: 0

像素风红黄绿三色灯泡

关于业务异常应该继承RuntimeException还是Exception,这个看似“习惯”的问题,实则直接关系到Spring事务的默认行为与工程设计的简洁性。

结论先行:业务异常必须继承RuntimeException。这不是编码风格之争,而是关乎事务一致性代码可维护性的工程原则。

一、为什么业务异常不该继承 Exception

如果你像下面这样定义业务异常:

public class BizException extends Exception {
}

看起来似乎合情合理,但它会立刻给你的项目带来两个棘手的后果。

1. 事务默认不会回滚

Spring 对声明式事务有一个默认规则:

  • RuntimeException 及其子类 → 自动回滚
  • Exception 及其子类(受检异常) → 不回滚

这意味着,当你的 Service 方法如下时:

@Transactional
public void create() throws BizException {
    // ... 一些数据库操作
    throw new BizException("库存不足");
}

已经执行的数据操作将不会回滚。 为了解决这个问题,你不得不做出选择:

  • 在每个@Transactional注解中手动指定 rollbackFor = BizException.class
  • 或者在代码中到处编写 try-catch 块来手动回滚

无论哪种方式,都直接增加了工程的复杂度和维护成本。

2. 调用链被迫“显式处理”

受检异常要求方法签名必须显式声明throws。于是,异常传递变成了这样:

  • Service 层抛出 BizException
  • Controller 层必须捕获或继续声明 throws
  • 调用链上的每一层都不得不处理这个语法负担

最终,原本用于表达业务规则的异常,却沦为了污染方法签名、增加模板代码的“语法噪音”。

动态切换的蓝白圆形图标

二、继承 RuntimeException 带来的工程收益

正确的定义方式应该如下:

public class BizException extends RuntimeException {
    public BizException(String message) {
        super(message);
    }
}

这样做的好处是直接且显著的:

  • 事务默认回滚:符合 Spring 的默认约定,无需额外配置。
  • 不污染方法签名:方法无需声明throws,调用链简洁。
  • 可随时抛出:在业务逻辑的任何地方,一旦发现状态不合法,即可直接抛出。

再配合一个全局异常处理器(例如使用 Spring MVC 的 @ExceptionHandler),收益会更大:

@ExceptionHandler(BizException.class)
public Result<?> handle(BizException e) {
    return Result.fail(e.getMessage());
}

通过这种异常处理机制,业务异常的语义事务回滚逻辑和HTTP响应格式被彻底解耦。业务代码只需关注核心逻辑和异常抛出,其余工作由框架统一接管。

动态切换的蓝白圆形图标

三、什么时候才考虑使用受检异常

那么,受检异常 (Exception) 就毫无用处了吗?并非如此。它适用于那些调用方“必须”且有能力处理的异常场景,例如:

  • IO 操作(文件不存在、读写权限问题)
  • 网络通信(连接超时、协议错误)
  • 外部系统调用(第三方API返回约定外的错误)

然而,关键在于,这些通常不属于“业务异常”的范畴

业务异常的本质,是用于表达业务流程中的非法状态或规则冲突,例如:

  • 参数校验不合法
  • 业务状态不允许执行当前操作
  • 领域规则不满足(如库存不足、余额不够)

对于这类异常,它们应该具备以下特点:

  • 可以随时抛出,不受方法签名约束
  • 能够自动触发事务回滚,保证数据一致性
  • 由框架统一处理并转换为用户友好的提示

一句话总结:业务异常是一种流程控制手段,而非对调用方的强制约束。 将其设计为非受检异常(RuntimeException),正是为了匹配这一核心定位。

希望这次的梳理能帮你理清思路。关于Java工程实践中的更多设计模式与最佳实践,欢迎在云栈社区与更多开发者交流探讨。

开心的星星眼卡通猫




上一篇:Java责任链模式实战:告别多层if嵌套,构建灵活处理流程
下一篇:AdonisJS路径遍历漏洞CVE-2026-21440分析:可致远程代码执行
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-24 16:15 , Processed in 0.275629 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表