应统一捕获dataaccessexception及其子类,在@controlleradvice中通过@exceptionhandler(dataaccessexception.class)实现全局处理,区分duplicatekeyexception、sqlgrammarexception等子类型返回定制化提示,并屏蔽敏感sql信息。

MyBatis-Plus 本身不直接抛出 DataAccessException,而是通过底层的 MyBatis 或 Spring JDBC 将数据库异常包装为 Spring 的 DataAccessException 子类(如 CannotAcquireLockException、DuplicateKeyException、SQLGrammarException 等)。统一捕获这类异常,核心在于利用 Spring 的全局异常处理机制。
使用 @ControllerAdvice 统一处理 DataAccessException
这是最常用且推荐的方式,适用于 Web 层(Spring MVC/Boot),能集中拦截所有控制器中抛出的 DataAccessException 及其子类:
- 创建一个全局异常处理器类,添加
@ControllerAdvice注解 - 用
@ExceptionHandler(DataAccessException.class)方法专门捕获数据库异常 - 根据具体子类型做差异化处理(如主键冲突、乐观锁失败、连接超时等)
示例:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(DataAccessException.class)
@ResponseBody
public Result handleDataAccessException(DataAccessException ex) {
if (ex instanceof DuplicateKeyException) {
return Result.fail("数据已存在,请检查重复项");
} else if (ex instanceof CannotAcquireLockException) {
return Result.fail("操作繁忙,请稍后重试");
} else if (ex instanceof SQLGrammarException) {
return Result.fail("数据库语句错误,请联系管理员");
} else if (ex.getCause() instanceof SQLException) {
SQLException sqlEx = (SQLException) ex.getCause();
if ("08S01".equals(sqlEx.getSQLState())) { // 通信链路异常
return Result.fail("数据库连接异常");
}
}
return Result.fail("数据库操作失败:" + ex.getMessage());
}
}
Service 层 try-catch + 自定义异常转换
若需在 Service 中提前干预(如重试、降级、日志增强),可在关键数据库操作处主动捕获并转换:
- 在 service 方法中用 try-catch 包裹
save()、updateById()等 MP 操作 - 捕获
DataAccessException后,封装为业务异常(如BusinessException)再抛出 - 避免把原始异常暴露给上层,便于统一响应格式和监控
注意:不要吞掉异常也不记录日志,否则难以排查问题。
配置 SQLExceptionTranslator 细粒度控制异常映射
Spring 默认使用 SQLStateSQLExceptionTranslator,但某些数据库(如 MySQL、Oracle)的错误码语义更明确。可自定义 translator 提升识别精度:
- 继承
SQLExceptionTranslator,重写doTranslate()方法 - 根据
SQLException.getSQLState()或getErrorCode()判断异常类型 - 注册为 bean,Spring 会自动用于 MyBatis-Plus 的异常包装过程
例如针对 MySQL 唯一键冲突(errno=1062),可精准转为 DuplicateKeyException,方便上层识别。
配合 MyBatis-Plus 的异常增强配置
MP 本身不干预异常类型,但可通过以下方式辅助异常治理:
- 开启
configuration.logPrefix=mybatis.查看 SQL 执行日志,定位异常 SQL - 使用
@TableName(autoResultMap = true)避免因 resultMap 错误导致的UncategorizedSQLException - 对敏感操作(如扣减库存)加分布式锁或版本号校验,从源头减少并发异常
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











