有必要,这是分层架构中异常处理的关键实践:DAO层抛出技术异常(如SQLException),Service层将其转换为语义明确的业务异常(如UserNotFoundException),既保障关注点分离、可读性与精准处理,又通过异常链保留原始错误信息。

有必要,而且是分层架构中异常处理的关键实践。
避免技术细节污染业务逻辑
SQLException 是数据库驱动层的原始错误,包含连接超时、语法错误、主键冲突等几十种具体情形。如果让 Service 层直接处理 SQLException,就等于要求业务代码去解析 SQLState、SQL 错误码或异常类名(如 SQLIntegrityConstraintViolationException),这明显违背了关注点分离原则。UserNotFoundException 则明确表达了“查不到用户”这一业务事实,与数据库怎么实现、用什么方言无关。
支撑可读性与可维护性
当 Controller 或调用方看到 UserNotFoundException,能立刻理解问题本质并决定如何响应(比如返回 404 或提示“用户不存在”);而看到 SQLException,只能被动记录日志或抛出泛化错误,无法做语义化决策。统一使用业务异常命名(如 UserAlreadyExistsException、InsufficientBalanceException),也让团队协作、文档编写和监控告警更直观。
为精准异常处理提供基础
Spring 的 DataAccessException 层次结构已将底层 SQLException 映射为语义子类: - DuplicateKeyException → 可转为 UserAlreadyExistsException - EmptyResultDataAccessException → 可转为 UserNotFoundException - DataIntegrityViolationException → 可转为 InvalidUserDataException 这种逐级映射不是简单包装,而是基于数据库反馈做出的业务判断。DAO 层只负责“执行”,Service 层才具备上下文(比如当前操作是根据 username 查询用户),因此必须由它完成这层语义跃迁。
保障异常链不被破坏
转换过程不是丢弃 SQLException,而是用带 cause 构造器封装: throw new UserNotFoundException("用户 " + username + " 未找到", e); 其中 e 就是捕获的 EmptyResultDataAccessException(它本身已封装原始 SQLException)。这样日志里能看到完整堆栈,运维可追溯到具体 SQL 和数据库状态,开发也能定位是 DAO 实现问题还是数据问题,而不是面对一个空泛的“用户未找到”干瞪眼。

















