应将 duplicatekeyexception 统一转换为自定义的 resourceconflictexception(继承 runtimeexception),在 @controlleradvice 中捕获并解析 sql 状态码或异常消息生成语义化提示(如“用户名已存在”),返回 409 conflict 状态码,并确保事务自动回滚。

在 Spring Boot 项目中,当数据库唯一索引冲突触发 DuplicateKeyException(底层通常是 JDBC 的 SQLIntegrityConstraintViolationException 或 Hibernate 的 ConstraintViolationException),直接抛出该异常对前端不友好。推荐统一转换为语义明确的自定义异常 ResourceConflictException,便于全局异常处理和 HTTP 状态码映射(如返回 409 Conflict)。
定义 ResourceConflictException
继承 RuntimeException,支持带消息和原因构造:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
public class ResourceConflictException extends RuntimeException {
public ResourceConflictException(String message) {
super(message);
}
public ResourceConflictException(String message, Throwable cause) {
super(message, cause);
}
}
在 @ControllerAdvice 中捕获并转换
使用全局异常处理器拦截 DuplicateKeyException,识别冲突原因后包装为 ResourceConflictException:
- 检查异常是否由唯一约束(如
UK_*、unique_*、constraint等关键词)或 SQL 状态码(如 PostgreSQL 的23505,MySQL 的1062)触发 - 提取冲突字段名(可选):解析异常消息或 SQL 错误码,生成更具体的提示,例如 “用户名已存在” 或 “邮箱已被注册”
- 重新抛出
ResourceConflictException,保留原始异常作为 cause,便于日志追踪
示例异常处理器片段
@ExceptionHandler(DuplicateKeyException.class)
public ResponseEntity<errorresponse> handleDuplicateKey(DuplicateKeyException e) {
String message = "资源冲突:操作违反唯一性约束";
// 可选:根据异常消息或 cause 提取更精确提示
if (e.getMostSpecificCause() instanceof SQLException sqlEx) {
String sqlState = sqlEx.getSQLState();
if ("23505".equals(sqlState) || "23000".equals(sqlState)) {
message = extractConflictMessageFromSqlMessage(e.getMessage());
}
}
ResourceConflictException conflictEx = new ResourceConflictException(message, e);
ErrorResponse error = new ErrorResponse("CONFLICT", message, System.currentTimeMillis());
return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
}</errorresponse>
确保事务边界清晰
注意 DuplicateKeyException 是运行时异常,Spring 默认只对未检查异常(RuntimeException 及其子类)进行事务回滚。确保你的 ResourceConflictException 继承自 RuntimeException,否则需显式标注 @Transactional(rollbackFor = ResourceConflictException.class)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










