Spring Boot中如何捕获SqlExceptionHelper异常实现数据库宕机邮件告警
解决方案
你遇到的异常本质是Spring DAO层封装抛出的DataAccessResourceFailureException,内部嵌套了Hibernate的JDBCConnectionException,无需实现SqlExceptionHelper.WarningHandler——该接口是用来处理SQL执行过程中的警告信息的,并不负责处理连接失败这类致命异常,之前的方案方向错误自然无法生效。
以下是3种适配不同场景的实现方案:
方案1:全局异常处理器(适配Controller层数据库操作)
如果你的数据库操作主要在接口请求链路里,用Spring自带的全局异常处理器即可直接捕获:
import org.springframework.dao.DataAccessResourceFailureException; import org.hibernate.exception.JDBCConnectionException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import lombok.extern.slf4j.Slf4j; @Slf4j @RestControllerAdvice public class GlobalDbExceptionHandler { // 注入你自己实现的邮件发送工具类 private final MailService mailService; public GlobalDbExceptionHandler(MailService mailService) { this.mailService = mailService; } @ExceptionHandler(value = {DataAccessResourceFailureException.class, JDBCConnectionException.class}) public void handleDbConnectFailure(Exception e) { log.error("数据库连接异常,触发告警", e); // 注意加去重逻辑,避免短时间大量异常重复发邮件 mailService.sendAlertMail("数据库宕机告警", e.getMessage()); } }
方案2:定时任务专属异常处理(适配你的报错场景)
你的错误日志明确是scheduling-1定时任务线程抛出的,Spring定时任务异常不会走全局Controller异常处理器,推荐用统一配置处理所有定时任务异常:
import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.dao.DataAccessResourceFailureException; import org.hibernate.exception.JDBCConnectionException; @Configuration public class SchedulerConfig implements SchedulingConfigurer { private final MailService mailService; public SchedulerConfig(MailService mailService) { this.mailService = mailService; } @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(10); scheduler.setThreadNamePrefix("scheduling-"); // 统一配置定时任务异常处理逻辑 scheduler.setErrorHandler(e -> { // 判断是否是数据库连接异常 boolean isDbConnectError = e instanceof DataAccessResourceFailureException || e.getCause() instanceof JDBCConnectionException || e.getMessage().contains("Unable to acquire JDBC Connection"); if (isDbConnectError) { log.error("定时任务触发数据库连接异常", e); // 加去重逻辑后发送告警邮件 mailService.sendAlertMail("数据库宕机告警", e.getMessage()); } }); scheduler.initialize(); taskRegistrar.setTaskScheduler(scheduler); } }
如果只有个别定时任务操作数据库,也可以直接在对应方法外套try-catch捕获对应异常即可。
方案3:全局异常监听(全场景兜底方案)
如果需要覆盖所有场景的数据库连接异常,包括非Controller、非定时任务的其他线程操作,可以用Spring事件监听机制做兜底:
import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import org.springframework.dao.DataAccessResourceFailureException; import org.hibernate.exception.JDBCConnectionException; import lombok.extern.slf4j.Slf4j; @Slf4j @Component public class DbExceptionListener { private final MailService mailService; // 简单去重:5分钟内只发1次告警 private static final long ALERT_INTERVAL = 5 * 60 * 1000; private long lastSendTime = 0; public DbExceptionListener(MailService mailService) { this.mailService = mailService; } @EventListener(classes = {DataAccessResourceFailureException.class, JDBCConnectionException.class}) public void handleDbException(Exception e) { log.error("全局捕获数据库连接异常", e); synchronized (this) { long now = System.currentTimeMillis(); if (now - lastSendTime > ALERT_INTERVAL) { mailService.sendAlertMail("数据库宕机告警", e.getMessage()); lastSendTime = now; } } } }
额外优化建议
可以调整Hikari连接池参数缩短异常感知时间,在application.properties中添加如下配置:
# 连接超时时间改成3秒,不用默认的30秒才抛出异常 spring.datasource.hikari.connection-timeout=3000 # 连接校验超时时间 spring.datasource.hikari.validation-timeout=2000
内容的提问来源于stack exchange,提问作者Diego Izquierdo Dussan
相关产品推荐
相关产品推荐

