当往数据库里插入数据主键重复时,系统会抛出异常
java.sql.SQLIntegrityConstraintViolationException
这时候我们会自定义一个全局异常处理器去捕获异常。
public class GlobalExceptionHandler {@ExceptionHandler(SQLIntegrityConstraintViolationException.class)public Result handleSQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException ex) {log.error("异常信息:用户已存在" );return Result.error("用户已存在");}@ExceptionHandler(Exception.class)public Result HandlerAllExpection(Exception ex) {log.error("异常信息:{}", ex.getMessage());return Result.error(ex.getMessage());}
//TODO 异常处理器的顺序存在问题
}
于是我自定义了一个类去捕获异常,但我发现无论如何捕获该异常,设置异常处理顺序,捕获到这个小异常总是在处理大的全局Expection之后。经过查询是因为
当往数据库中插入数据时,如果主键重复,通常会导致 SQLIntegrityConstraintViolationException
被抛出。这个异常在 Spring 框架中会被进一步包装为更通用的异常类型,主要是 DataIntegrityViolationException
。
在Java中,异常包装(Exception Wrapping)是一种将一个异常封装在另一个异常中的技术。这种做法可以帮助保留原始异常的堆栈信息,同时添加更多上下文,以便于调试和错误处理。
- 保留原始异常信息:通过将原始异常作为参数传递给新的异常,可以保留其堆栈跟踪信息。
- 添加上下文信息:新的异常可以包含有助于理解错误上下文的额外信息。
- 统一异常处理:可以在不同层次的代码中捕获异常并抛出统一的异常类型,简化错误处理流程。
2. 使用异常包装
接下来,创建一个可能会抛出异常的方法,并在此方法中进行异常包装:
public class ExceptionWrapperExample {public static void riskyMethod() throws CustomException {try {// 可能抛出异常的代码int result = 1 / 0; // 这里会抛出 ArithmeticException} catch (ArithmeticException e) {// 捕获到异常后,抛出自定义异常并包装原始异常throw new CustomException("An error occurred in riskyMethod", e);}}public static void main(String[] args) {try {riskyMethod(); // 调用可能抛出异常的方法} catch (CustomException e) {// 处理自定义异常System.out.println("Caught a CustomException: " + e.getMessage());System.out.println("Original exception: " + e.getCause()); // 获取原始异常e.printStackTrace(); // 打印堆栈跟踪}}
}
输出示例
运行上述代码时,可能会得到类似以下的输出:
Caught a CustomException: An error occurred in riskyMethod
Original exception: java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zeroat ExceptionWrapperExample.riskyMethod(ExceptionWrapperExample.java:5)at ExceptionWrapperExample.main(ExceptionWrapperExample.java:12)
总结
通过异常包装,可以在Java中有效地处理和传递异常。这样做不仅能保持原始异常的信息,还能为上层调用者提供更多的上下文信息。