需要统一异常转化层,将mybatis、jpa、redis等框架的底层异常(如sqlexception、redisconnectionfailureexception)统一转为项目自定义业务异常,避免上层代码被技术异常污染,并通过错误码、日志上下文提升可观测性。

直接用统一异常转化层,把 MyBatis、JPA、Redis、MongoDB 等不同持久化框架抛出的底层异常,全部转成你项目自己的业务异常类型,避免上层代码被各种 SQLException、PersistenceException、RedisConnectionFailureException 等污染。
为什么需要这层转化
不同持久化框架对同一类问题的异常表达完全不同:
- 数据库连接失败:MyBatis 抛
SQLException,JPA 抛PersistenceException或CannotCreateTransactionException,Redis 抛RedisConnectionFailureException - 主键冲突:MySQL 报错码 1062 → MyBatis 封装为
SQLIntegrityConstraintViolationException,而 PostgreSQL 是PSQLException,JPA 可能再包一层DataIntegrityViolationException - 超时:Redis 超时是
RedisTimeoutException,Druid 连接池超时是SQLException带 “timeout” 字符串,但堆栈完全无关
不转化就等于让 Service 层或 Controller 层去识别十几种异常类型,既难维护,又破坏分层契约。
核心实现方式:在 DAO/Repository 层拦截并重抛
不要等异常冒泡到 Service 层才处理。转化动作必须发生在数据访问层出口处,即每个 Repository 方法执行完后、返回前完成兜底转换。
- Spring 项目中,推荐用
@Repository+@ExceptionHandler组合(注意:不是全局的@RestControllerAdvice,而是仅作用于 DAO 层) - 更稳妥的方式是定义抽象基类
BaseRepository,所有具体 Repository 继承它,并在模板方法中统一 try-catch 持久化调用 - 若用 MyBatis-Plus,可配合
MybatisPlusExceptionTranslator扩展点;若用 Spring Data JPA,可覆盖JpaVendorAdapter的异常翻译逻辑
转化规则要映射到业务语义,而非技术细节
别写“数据库连接失败”,而要区分场景:
-
连接不可达 → 转为
SystemUnavailableException(错误码SYS_503),表示服务暂时不可用,前端可提示“系统繁忙,请稍后再试” -
事务超时 → 转为
BusinessTimeoutException(错误码BIZ_408),说明业务操作耗时过长,可能需优化流程或提示用户重试 -
唯一约束冲突 → 转为
DuplicateResourceException(错误码RES_409),明确指向“资源已存在”,前端可引导跳转或刷新列表 -
查询无结果 → 不算异常!应返回空对象或 Optional,只有「预期必有却无」才抛
ResourceNotFoundException(如根据 ID 查用户却不存在)
配合错误码体系与日志上下文
转化不是简单换异常类型,还要补全可观测信息:
- 保留原始异常作为 cause,确保堆栈可追溯
- 注入当前操作的模块名、表名、SQL 片段(脱敏后)、traceId,写入 warn 日志
- 错误码字段必须和全局
ErrorCode枚举对齐,例如DB_CONN_FAILURE("SYS_503", "数据库连接失败") - 前端响应体中的
code字段,只传枚举 code 字符串,不传数字或类名
这样,运维查日志时能快速定位是哪个库、哪条语句、在哪个微服务节点出的问题;前端也无需解析异常类名,只按 code 做 UI 分支即可。










