You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 21:15:00