spring boot 全局异常处理捕获数据不一致异常的核心做法是定义一个继承自 dataintegrityviolationexception 的自定义异常类,并在 @controlleradvice 中针对该类型编写专用的 @exceptionhandler 方法。当数据库约束(如唯一索引、外键)被违反时,底层驱动抛出的原始异常会被 spring 包装为 dataintegrityviolationexception,此时通过解析其嵌套的根异常或 sql 错误码,即可精准定位冲突字段并返回友好的前端提示。

如何区分不同的数据约束冲突
在 @ExceptionHandler 中,可以通过检查 DataIntegrityViolationException 的 getRootCause() 来获取具体的数据库驱动异常对象。不同数据库(如 MySQL 的 MySQLIntegrityConstraintViolationException)会提供特定的错误码或消息模式,开发者可以据此判断是主键冲突、唯一键冲突还是外键约束失败,从而返回不同的业务状态码。

import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<String> handleDataIntegrity(DataIntegrityViolationException ex) {
Throwable rootCause = ex.getRootCause();
String message = "数据操作失败";
if (rootCause != null && rootCause.getMessage() != null) {
String msg = rootCause.getMessage().toLowerCase();
if (msg.contains("duplicate") || msg.contains("unique")) {
message = "数据重复:请检查输入的唯一性字段";
} else if (msg.contains("foreign key")) {
message = "关联数据不存在:无法建立关联关系";
}
}
return ResponseEntity.status(HttpStatus.CONFLICT).body(message);
}
}如何在 Service 层提前校验避免异常抛出
虽然全局异常处理能兜底,但在高并发场景下,依赖数据库异常回滚性能较差。更优的做法是在 Service 层使用 @Transactional 结合乐观锁或前置查询来预判。例如,在更新记录前再次查询当前版本号或状态,若发现与预期不符则直接抛出业务异常 BusinessException,这样既避免了数据库层面的资源浪费,又能保证事务的一致性。

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
@Transactional
public void updateOrderStatus(Long orderId, String newStatus) {
// 模拟前置校验逻辑
Order order = orderRepository.findById(orderId).orElseThrow(() -> new RuntimeException("订单不存在"));
if (!order.getStatus().equals("PENDING")) {
throw new BusinessException("订单状态已变更,无法执行此操作");
}
order.setStatus(newStatus);
orderRepository.save(order);
}
}如何处理批量插入中的部分数据不一致
在执行批量插入(Batch Insert)时,如果其中一条数据违反约束,默认情况下整个事务会回滚,导致所有数据丢失。为解决此问题,可以使用 JDBC 的 addBatch 配合 executeBatch 时的异常捕获机制,或者使用 MyBatis-Plus 等框架提供的忽略错误配置。具体做法是在 DAO 层循环调用单条插入并单独捕获异常,记录失败项而不停止整体流程,最终返回成功与失败的明细列表供前端展示。


















