java中唯一键冲突应统一捕获sqlintegrityconstraintviolationexception,通过sql状态码(如"23000"、"23505")识别,正则提取字段名并映射为业务提示,结合@controlleradvice返回结构化错误响应。

Java 中数据库唯一键冲突异常(如 MySQL 的 1062 Duplicate entry 或 PostgreSQL 的 unique_violation)通常抛出为 SQLIntegrityConstraintViolationException(JDBC 4.1+),其父类是 SQLException。要在全局友好捕获并统一处理,核心思路是:**拦截底层 SQL 异常 → 识别唯一约束违规 → 转换为业务友好的自定义异常或标准化响应**。
统一异常处理器(Spring Boot 推荐)
使用 @ControllerAdvice + @ExceptionHandler 捕获所有控制器层抛出的异常:
- 针对
SQLIntegrityConstraintViolationException做精准匹配,避免误捕其他 SQL 异常 - 解析异常消息或 SQL 状态码(
getSQLState())判断是否为唯一键冲突(例如 MySQL 返回"23000",PostgreSQL 返回"23505") - 提取冲突字段名(可正则匹配异常消息中的列名,如
"Duplicate entry 'xxx' for key 'uk_user_email'"→ 提取email) - 返回结构化错误响应,如
{"code": 400, "message": "邮箱已被注册"}
DAO 层预判 + 自定义异常封装
在执行插入/更新前,不依赖异常兜底,而是主动检查(适合高一致性要求场景):
- 对关键唯一字段(如 username、email)先查库确认是否存在
- 若存在,直接抛出自定义异常(如
DuplicateResourceException),由全局处理器统一转译 - 优点:异常语义清晰、无副作用;缺点:多一次查询,需注意并发窗口(可用数据库唯一索引 + 兜底异常双保险)
利用 JPA/Hibernate 的特定异常映射
如果用 Spring Data JPA,Hibernate 会将底层 SQL 异常包装为更语义化的异常:
- MySQL 唯一键冲突 →
DataIntegrityViolationException(含原始SQLException) - 可在此异常的
getCause()中递归查找SQLIntegrityConstraintViolationException - 推荐在全局处理器中同时捕获
DataIntegrityViolationException和原生SQLException,提高兼容性
数据库方言适配与消息解析技巧
不同数据库报错格式差异大,建议封装一个工具方法统一识别:
- 检查
getSQLState():MySQL 是"23000",PostgreSQL 是"23505",Oracle 是"23000"(但需结合getErrorCode()) - 正则提取字段名:
Pattern.compile("for key '.*?(\w+)_([^']+)'|for key '([^']+)'")(适配常见命名习惯) - 建立映射表:
{"uk_user_email" → "邮箱", "uk_order_no" → "订单号"},提升提示友好度
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











