注解名称 | 来源框架 / 规范 | 典型使用场景 | 版本(引入年份) | 是否推荐使用 |
---|---|---|---|---|
@DataAccessException |
Spring Framework | 封装 JDBC/MyBatis 等数据访问异常 | Spring 1.0(2004) | ✅ |
@Transactional |
Spring Framework | 声明数据库事务(如 Service 层操作) | Spring 2.0(2007) | ✅ |
@ExceptionHandler |
Spring MVC | 方法内捕获并处理特定异常(如 NullPointerException ) |
Spring 3.0(2009) | ✅ |
@ResponseStatus |
Spring MVC | 标记异常对应的 HTTP 状态(如 404、500) | Spring 3.0(2009) | ✅ |
@Valid |
JSR-303 / Hibernate Validator | 校验请求参数(如 @RequestBody 接收的 JSON) |
Spring 3.0(2009) | ✅ |
@ControllerAdvice |
Spring MVC | 统一处理多个 Controller 的全局异常 | Spring 3.2(2013) | ✅ |
@DataAccessException
引入背景 不同的持久化技术(如 JDBC、Hibernate、MyBatis 等)抛出的异常类型不同,导致业务代码难以统一处理。
Spring 提供了 DataAccessException 作为统一的异常基类,屏蔽底层实现细节。且Spring 定义了丰富的 DataAccessException 子类,提供更清晰的错误语义。
RuntimeException
└── DataAccessException
├── NonTransientDataAccessException
│ └── DuplicateKeyException ✅插入或更新时违反唯一约束(如主键/唯一索引冲突)
│ └── IncorrectUpdateSemanticsDataAccessException
├── TransientDataAccessException
│ └── CannotAcquireLockException
│ └── TransactionSystemException
└── UncategorizedSQLException
@DataAccessException 典型用法
1、DAO 层抛出异常
2、Service 层捕获并处理异常
public void processUser(Long id) {
try {
User user = userRepository.getUserById(id);
} catch (EmptyResultDataAccessException e) {
// 处理用户不存在的情况
throw new UserNotFoundException("用户不存在");
} catch (DataAccessException e) { ✅这里catch主所有DataAccessException及其子类异常做封装处理
// 统一处理数据库异常
log.error("数据库访问异常", e);
throw new SystemInternalException("系统内部错误");
}
}
3.、Controller 层统一异常处理
结合 @ControllerAdvice
和 @ExceptionHandler
做全局异常响应:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EmptyResultDataAccessException.class)
public ResponseEntity<String> handleUserNotFound() {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("资源不存在");
}
@ExceptionHandler(DataAccessException.class) ✅DataAccessException类异常处理出口
public ResponseEntity<String> handleDatabaseError(DataAccessException ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("数据库异常:" + ex.getMessage());
}
}
@Transactional
引入背景 在早期 Java EE 或 JDBC 编程中,事务需要手动控制
Connection conn = dataSource.getConnection();
try {
conn.setAutoCommit(false);
// 执行多个 SQL 操作
conn.commit();
} catch (SQLException e) {
conn.rollback();
} finally {
conn.close();
}
为了解决上述问题,Spring 提出了声明式事务管理机制,并通过 @Transactional 注解实现这一目标。其核心设计思想是将事务控制从业务逻辑中解耦出来,交由框架自动处理。
@Transactional 典型用法
需要横展开
@ExceptionHandler
引入背景 在早期开发中,开发者通常在 Controller 方法内部使用 try-catch 捕获异常并返回错误响应。不同 Controller 或方法各自处理异常,导致异常响应格式不统一,不利于前端解析。
@GetMapping("/user/{id}")
public ResponseEntity<?> getUser(@PathVariable Long id) {
try {
return ResponseEntity.ok(userService.getUserById(id));
} catch (UserNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("用户不存在");
}
}
为了解决上述问题,Spring MVC 在 3.0 版本中引入了 @ExceptionHandler 注解。
@ResponseStatus
引入背景 在没有 @ResponseStatus 的早期开发中,开发者通常通过以下方式设置 HTTP 状态码:
1. 手动返回 ResponseEntity
@GetMapping("/user/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
if (id <= 0) {
return ResponseEntity.badRequest().build();
}
User user = userService.findById(id);
return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
}
2. 在 @ExceptionHandler 中显式设置状态码
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<String> handleUserNotFound() {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("用户不存在");
}
为了简化状态码的设置流程,提高代码可读性和可维护性,Spring 在 2.5 版本 引入了 @ResponseStatus 注解。
@Valid
引入背景 在没有 @Valid 的时代,开发者通常通过以下方式进行参数校验:
@PostMapping("/users")
public ResponseEntity<?> createUser(@RequestBody User user) {
if (user.getName() == null || user.getName().isEmpty()) {
return ResponseEntity.badRequest().body("用户名不能为空");
}
if (user.getAge() < 0) {
return ResponseEntity.badRequest().body("年龄不能为负数");
}
// ...
}
为了简化参数校验流程,提高代码可读性和可维护性,Spring 在其 MVC 模块中集成了 Bean Validation 规范,并引入了 @Valid 注解。
@ControllerAdvice
引入背景 在没有 @ControllerAdvice 的时代,开发者通常通过以下方式进行异常处理:
@RestController
public class UserController {
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) {
// ...
}
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<String> handleUserNotFound() {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("用户不存在");
}
}
为了实现全局统一的异常处理机制,Spring 在 3.2 版本(约 2013 年) 引入了 @ControllerAdvice 注解。
@ControllerAdvice 是 Spring 提供的一个全局增强注解,常用于统一异常处理、数据绑定和模型属性增强。它适用于所有带有 @Controller 或 @RestController 注解的控制器类。
SpringMVC @ExceptionHandler典型用法
SpringMVC @ResponseStatus 典型用法
@Valid 典型用法
SpringMVC @ControllerAdvice 典型用法