如何在Spring Boot应用中为API设置超时并关闭数据库连接?
解决Spring Boot API超时30秒关闭数据库连接并返回错误的方案
你提到的两个配置之所以无效,是因为它们的作用场景和你要解决的问题不匹配:
server.tomcat.connection-timeout:控制Tomcat服务器接受客户端连接的超时时间,并非API业务处理的超时。spring.mvc.async.request-timeout:仅对异步请求(比如返回Callable、DeferredResult的接口)生效,同步接口不会触发该超时。
下面是几个可行的解决方案,从API层面到数据库层面全覆盖:
1. 同步接口全局超时控制(AOP实现)
通过AOP环绕通知,给所有API方法设置超时时间,超时后中断线程并关闭数据库连接:
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @Aspect @Component public class ApiTimeoutAspect { private final ExecutorService executor = Executors.newCachedThreadPool(); @Around("execution(* com.yourpackage.controller..*(..))") public Object handleApiTimeout(ProceedingJoinPoint joinPoint) throws Throwable { try { // 设置30秒超时 return executor.submit(joinPoint::proceed).get(30, TimeUnit.SECONDS); } catch (TimeoutException e) { // 中断当前线程,触发数据库连接的中断逻辑 Thread.currentThread().interrupt(); // 手动关闭当前请求关联的数据库连接(示例,根据你的数据源实现调整) // Connection conn = ...; // if (conn != null && !conn.isClosed()) { // conn.close(); // } throw new RuntimeException("请求超时,请稍后重试"); } } }
2. 数据库层面强制超时
即使API层面的超时触发,数据库查询也可能仍在执行,因此必须在数据库层设置查询超时,避免连接资源浪费:
针对HikariCP数据源(Spring Boot默认)
在application.yml中添加:
spring: datasource: hikari: connection-timeout: 30000 # 获取连接的超时时间 idle-timeout: 600000 # 连接空闲超时 max-lifetime: 1800000 # 连接最大存活时间 # MySQL额外添加socket超时参数 jdbc-url: jdbc:mysql://localhost:3306/db?connectTimeout=30000&socketTimeout=30000
针对MyBatis
在Mapper接口方法上添加超时配置:
@Options(timeout = 30000) @Select("SELECT * FROM your_table WHERE id = #{id}") YourEntity getById(Long id);
针对JPA
在application.yml中添加全局查询超时:
spring: jpa: properties: javax.persistence.query.timeout: 30000
3. 全局异常处理返回统一错误
用@ControllerAdvice捕获超时相关异常,返回友好的错误响应:
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import java.util.HashMap; import java.util.Map; @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler({RuntimeException.class, TimeoutException.class}) @ResponseBody public Map<String, Object> handleTimeoutException(Exception e) { Map<String, Object> result = new HashMap<>(); result.put("code", 504); result.put("message", "请求超时,请稍后重试"); result.put("detail", e.getMessage()); return result; } }
4. 异步接口超时优化(若接口为异步实现)
如果部分接口是异步实现,确保spring.mvc.async.request-timeout配置正确,同时结合异步线程池的超时设置:
spring: mvc: async: request-timeout: 30000
自定义异步线程池并设置超时:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; @Configuration public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(20); executor.setThreadNamePrefix("Async-"); executor.setAwaitTerminationSeconds(30); executor.setWaitForTasksToCompleteOnShutdown(true); executor.initialize(); return executor; } }
内容的提问来源于stack exchange,提问作者Sangeetharaj
相关产品推荐
相关产品推荐

