spring boot 全局异常处理无法直接捕获序列号耗尽异常,因为该异常通常由数据库驱动或连接池在获取连接时抛出,属于运行时异常且未被 spring mvc 的默认异常解析器覆盖。要捕获并处理这种情况,需要自定义一个实现 handlerexceptionresolver 接口的 bean,并在其中显式检查异常类型,将序列号耗尽相关的异常(如 sqlexception 中包含特定错误码的情况)转换为统一的业务响应。

如何识别序列号耗尽的具体异常类型
序列号耗尽通常表现为数据库返回特定的错误码,例如 MySQL 的 Too many connections 或 Oracle 的 ORA-00018。这些异常最终会包装成 org.springframework.dao.DataIntegrityViolationException 或直接是 java.sql.SQLException。因此,第一步是确定底层抛出的确切异常类及其包含的错误信息或错误码,以便在解析器中进行精确匹配。

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
@Component
public class SequenceExhaustionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if (ex instanceof SQLException) {
SQLException sqlEx = (SQLException) ex;
// 假设错误码为 1040 代表连接数过多/序列号耗尽
if (sqlEx.getErrorCode() == 1040 || sqlEx.getMessage().contains("Too many connections")) {
try {
response.setStatus(503);
response.getWriter().write("{\"error\": \"Sequence exhausted\"}");
} catch (Exception e) {
e.printStackTrace();
}
return new ModelAndView();
}
}
return null;
}
}
上述代码定义了一个名为 SequenceExhaustionResolver 的组件,它实现了 HandlerExceptionResolver 接口。在 resolveException 方法中,首先判断异常是否为 SQLException 类型。如果是,则进一步检查其错误码或消息内容是否匹配序列号耗尽的特征。一旦匹配成功,便设置 HTTP 状态码为 503,并写入 JSON 格式的响应体。如果异常不匹配,则返回 null,让其他解析器继续处理。
如何确保解析器优先级高于默认处理器
Spring Boot 内置了多个异常解析器,如 ExceptionHandlerExceptionResolver。为了确保自定义的序列号耗尽解析器能够优先执行,必须为其指定较高的优先级。可以通过实现 Ordered 接口并重写 getOrder 方法,或者使用 @Order 注解来设定顺序值。数值越小,优先级越高。

import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class HighPrioritySequenceResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if (ex instanceof SQLException) {
SQLException sqlEx = (SQLException) ex;
if (sqlEx.getErrorCode() == 1040) {
try {
response.setStatus(503);
response.getWriter().write("{\"error\": \"High Priority Exhaustion\"}");
} catch (Exception e) {
e.printStackTrace();
}
return new ModelAndView();
}
}
return null;
}
}
在这个改进的版本中,通过添加 @Order(Ordered.HIGHEST_PRECEDENCE) 注解,确保了 HighPrioritySequenceResolver 在所有其他异常解析器之前被调用。这保证了即使发生序列号耗尽,也能第一时间被捕获并返回特定的 503 响应,而不是被默认的 500 错误页面覆盖。这种高优先级的设置对于关键资源的异常处理至关重要,避免了因默认处理逻辑导致的响应延迟或不准确。
基于程序中某个输入、条件或结果的具体问题
当程序接收到一个导致数据库连接池耗尽的请求输入时,系统会立即抛出 SQLException。此时,自定义解析器会拦截该异常,并返回 503 状态码。验证这一行为的关键在于观察响应头中的状态码以及响应体的内容。如果配置正确,客户端将收到明确的“服务暂时不可用”提示,而非通用的服务器内部错误。











