首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >MySQL数据库宕机后报错com.alibaba.druid.pool.DataSourceClosedException

MySQL数据库宕机后报错com.alibaba.druid.pool.DataSourceClosedException

原创
作者头像
turingcao
发布2025-11-03 11:47:59
发布2025-11-03 11:47:59
2860
举报

背景

依赖组件版本

  • spring-boot-starter-parent:2.4.3
  • mybatis-plus-boot-starter:3.4.1
  • dynamic-datasource-spring-boot-starter:3.4.1
  • druid-spring-boot-starter:1.2.21
  • mysql-connector-java:5.1.49

连接池配置

代码语言:yaml
复制
spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      druid:
        filters: stat
        initialSize: 5
        minIdle: 5
        maxActive: 50
        maxWait: 60000
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        testWhileIdle: true
        testOnBorrow: true
        testOnReturn: false
        validationQuery: SELECT 1
        removeAbandoned: true
        removeAbandonedTimeoutMillis: 300000
        logAbandoned: true

遇到问题

当数据后宕机后,服务报以下错误,数据库连接池背关闭,即使数据库恢复后,服务也无法恢复,需要重启服务

代码语言:txt
复制
2025-10-31 19:14:43 xxx-xxx-xxx ERROR Druid-ConnectionPool-Create-1973861638 com.alibaba.druid.pool.DruidDataSource [DruidDataSource.java:2969] create conne
ction Exception, url: jdbc:mysql://xxx.xxx.xxx:3306/db?characterEncoding=utf-8&allowMultiQueries=true&connectTimeout=60000&socketTimeout=3000
00&autoReconnect=true&useSSL=false, errorCode 0, state 08001
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.

Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is com.alibaba.druid.pool.DataSourceClosedException: dataSource already closed at Fri Oct 31 19:14:43 CST 2025

原因

问题在于 com.mysql.jdbc.ConnectionImpl#connectWithRetries,默认在未配置重试次数和间隔的时候,最多重试3次,每次间隔2s,将不会再进行重试

代码语言:java
复制
private void connectWithRetries(boolean isForReconnect, Properties mergedProps) throws SQLException {
        double timeout = getInitialTimeout();
        boolean connectionGood = false;

        Exception connectionException = null;

        for (int attemptCount = 0; (attemptCount < getMaxReconnects()) && !connectionGood; attemptCount++) {
            try {
                if (this.io != null) {
                    this.io.forceClose();
                }

                coreConnect(mergedProps);
                pingInternal(false, 0);

                boolean oldAutoCommit;
                int oldIsolationLevel;
                boolean oldReadOnly;
                String oldCatalog;

                synchronized (getConnectionMutex()) {
                    this.connectionId = this.io.getThreadId();
                    this.isClosed = false;

                    // save state from old connection
                    oldAutoCommit = getAutoCommit();
                    oldIsolationLevel = this.isolationLevel;
                    oldReadOnly = isReadOnly(false);
                    oldCatalog = getCatalog();

                    this.io.setStatementInterceptors(this.statementInterceptors);
                }

                // Server properties might be different from previous connection, so initialize again...
                initializePropsFromServer();

                if (isForReconnect) {
                    // Restore state from old connection
                    setAutoCommit(oldAutoCommit);

                    if (this.hasIsolationLevels) {
                        setTransactionIsolation(oldIsolationLevel);
                    }

                    setCatalog(oldCatalog);
                    setReadOnly(oldReadOnly);
                }

                connectionGood = true;

                break;
            } catch (Exception EEE) {
                connectionException = EEE;
                connectionGood = false;
            }

            if (connectionGood) {
                break;
            }

            if (attemptCount > 0) {
                try {
                    Thread.sleep((long) timeout * 1000);
                } catch (InterruptedException IE) {
                    // ignore
                }
            }
        } // end attempts for a single host

        if (!connectionGood) {
            // We've really failed!
            SQLException chainedEx = SQLError.createSQLException(
                    Messages.getString("Connection.UnableToConnectWithRetries", new Object[] { Integer.valueOf(getMaxReconnects()) }),
                    SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE, getExceptionInterceptor());
            chainedEx.initCause(connectionException);

            throw chainedEx;
        }

        if (getParanoid() && !getHighAvailability()) {
            this.password = null;
            this.user = null;
        }

        if (isForReconnect) {
            //
            // Retrieve any 'lost' prepared statements if re-connecting
            //
            Iterator<Statement> statementIter = this.openStatements.iterator();

            //
            // We build a list of these outside the map of open statements, because in the process of re-preparing, we might end up having to close a prepared
            // statement, thus removing it from the map, and generating a ConcurrentModificationException
            //
            Stack<Statement> serverPreparedStatements = null;

            while (statementIter.hasNext()) {
                Statement statementObj = statementIter.next();

                if (statementObj instanceof ServerPreparedStatement) {
                    if (serverPreparedStatements == null) {
                        serverPreparedStatements = new Stack<Statement>();
                    }

                    serverPreparedStatements.add(statementObj);
                }
            }

            if (serverPreparedStatements != null) {
                while (!serverPreparedStatements.isEmpty()) {
                    ((ServerPreparedStatement) serverPreparedStatements.pop()).rePrepare();
                }
            }
        }
    }

解决方案

调整参数

代码语言:yaml
复制
spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      druid:
        filters: stat
        initialSize: 5
        minIdle: 5
        maxActive: 50
        maxWait: 60000
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        testWhileIdle: true
        testOnBorrow: true
        testOnReturn: false
        validationQuery: SELECT 1
        removeAbandoned: true
        removeAbandonedTimeoutMillis: 300000
        logAbandoned: true
      datasource:
        master:
          type: com.alibaba.druid.pool.DruidDataSource
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://xxx.xxx.xxx:3306/orca?characterEncoding=utf-8&allowMultiQueries=true&connectTimeout=60000&socketTimeout=300000&autoReconnect=true&useSSL=false&maxReconnects=6000&initialTimeout=10

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
    • 依赖组件版本
    • 连接池配置
    • 遇到问题
  • 原因
  • 解决方案
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档