全局捕获数据库异常需用@RestControllerAdvice拦截DataAccessException及其子类,精准提取SQLException并解析SQLState或errorCode,映射为语义化提示,响应脱敏且结构化。

数据库操作异常的全局捕获,核心是拦截 Spring 封装后的 DataAccessException 及其子类,并从异常链中精准提取底层数据库真实错误,再统一返回结构化响应。
用 @ControllerAdvice 拦截 DataAccessException
Spring MVC/Boot 推荐使用 @RestControllerAdvice 配合 @ExceptionHandler(DataAccessException.class) 实现 Web 层集中拦截:
- 该方式覆盖所有控制器中由 MyBatis-Plus、JDBC 或 JPA 触发的数据库异常
- 无需在每个 Service 或 Controller 中重复 try-catch
- 配合
@ResponseBody或ResponseEntity可直接输出 JSON 响应
区分具体子类型做语义化处理
不能只捕获顶层 DataAccessException,要判断实际子类以给出准确提示:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
DuplicateKeyException→ 提示“数据已存在,请检查手机号/用户名等唯一字段” -
CannotAcquireLockException→ 提示“操作冲突,请稍后重试”(常见于乐观锁或行锁竞争) -
SQLGrammarException→ 提示“系统异常,请联系管理员”,不暴露 SQL 细节 -
DataIntegrityViolationException→ 进入深层 cause 解析,定位约束类型(见下一项)
从异常链提取真实数据库约束信息
Spring 的包装异常(如 DataIntegrityViolationException)本身不含字段名或约束名,需递归遍历 getCause() 找到最内层 SQLException:
- 写工具方法安全遍历:
while (ex != null && !(ex instanceof SQLException)) { ex = ex.getCause(); } - 优先读取
getSQLState():PostgreSQL 用"23505"(唯一键冲突),MySQL 用getErrorCode() == 1062 - 正则提取消息中的字段或约束名:如 PostgreSQL 报错含
key (email)=(test@x.com) already exists,可提取email字段用于前端高亮
屏蔽敏感信息并统一响应格式
生产环境必须避免返回原始 SQL、堆栈或数据库连接详情:
- 响应体只包含
code、msg、timestamp等标准字段 - 日志中记录完整异常(含 cause 链),但响应中仅返回脱敏后提示
- 对
SQLException的getLocalizedMessage()不直接透出,改用预设文案映射

















