ホームページ > Java > &#&チュートリアル > springboot druid データベース接続プールが接続失敗後に再接続し続ける問題を解決する方法

springboot druid データベース接続プールが接続失敗後に再接続し続ける問題を解決する方法

王林
リリース: 2023-05-21 11:28:25
転載
3238 人が閲覧しました

個人用の Alibaba Cloud テスト マシンを使用したときに、リアルタイム出力ログを表示したところ、データベース接続が失敗した後、サーバーが再接続を試行し続けていることがわかりました。当初はシステムが継続的に攻撃を受けていると考えられましたが、サービスを再開したところ、継続的な再接続は発生しなくなりました。次の出力ログを確認してください:

2022-02-09 11:04:58.896 ERROR 16876 --- [eate-1550991149] com.alibaba.druid.pool.DruidDataSource : create connection SQLException, URL: jdbc:mysql://47.98.67,98:1234/test?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC、errorCode 1045、state 28000

java.sql.SQLException: ユーザー ' のアクセスが拒否されました。 root' @'113.90.123.76' (パスワードを使用: YES)
at com.mysql.cj.jdbc.Exceptions.SQLError.createSQLException(SQLError.java:129) ~[mysql-connector-java-8.0.16. jar: 8.0.16]
com.mysql.cj.jdbc.Exceptions.SQLError.createSQLException(SQLError.java:97) ~[mysql-connector-java-8.0.16.jar:8.0.16]
com.mysql.cj.jdbc.Exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.16.jar:8.0.16]
com.mysql.cj で。 jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:835) ~[mysql-connector-java-8.0.16.jar:8.0.16]
at com.mysql.cj.jdbc.ConnectionImpl.(ConnectionImpl .java :455) ~[mysql-connector-java-8.0.16.jar:8.0.16]
com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:240) ~[mysql-connector] -java -8.0.16.jar:8.0.16]
com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:199) ~[mysql-connector-java-8.0.16.jar:8.0] .16 ]
com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:156) ~[druid-1.1.10.jar:1.1.10]
com.alibaba.druid.filter .stat .StatFilter.connection_connect(StatFilter.java:218) ~[druid-1.1.10.jar:1.1.10]
com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:150) ~ [druid -1.1.10.jar:1.1.10]
com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1560) ~[druid-1.1.10.jar:1.1.10]
com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1623) ~[druid-1.1.10.jar:1.1.10]
com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread .run (DruidDataSource.java:2468) ~[druid-1.1.10.jar:1.1.10]

上記の druid データベース接続プールのプロンプトが常に表示されることに注意してください。それは druid 接続プールの問題である可能性があり、druid Maven 依存関係を削除した後は、リクエスト インターフェイスでの再接続の問題は発生しません。

Druid 再接続の理由

上記のソース コードの最後の行 DruidDataSource.java:2468 を見つけて、CreateConnectionThread で接続スレッドを作成し、CreateConnectionThread のソース コードを確認します。

public class CreateConnectionThread extends Thread {

        public CreateConnectionThread(String name){
            super(name);
            this.setDaemon(true);
        }

        public void run() {
            initedLatch.countDown();

            long lastDiscardCount = 0;
            int errorCount = 0;
            for (;;) {
                // addLast
                try {
                    lock.lockInterruptibly();
                } catch (InterruptedException e2) {
                    break;
                }

                long discardCount = DruidDataSource.this.discardCount;
                boolean discardChanged = discardCount - lastDiscardCount > 0;
                lastDiscardCount = discardCount;

                try {
                    boolean emptyWait = true;

                    if (createError != null
                            && poolingCount == 0
                            && !discardChanged) {
                        emptyWait = false;
                    }

                    if (emptyWait
                            && asyncInit && createCount < initialSize) {
                        emptyWait = false;
                    }

                    if (emptyWait) {
                        // 必须存在线程等待,才创建连接
                        if (poolingCount >= notEmptyWaitThreadCount //
                                && !(keepAlive && activeCount + poolingCount < minIdle)) {
                            empty.await();
                        }

                        // 防止创建超过maxActive数量的连接
                        if (activeCount + poolingCount >= maxActive) {
                            empty.await();
                            continue;
                        }
                    }

                } catch (InterruptedException e) {
                    lastCreateError = e;
                    lastErrorTimeMillis = System.currentTimeMillis();

                    if (!closing) {
                        LOG.error("create connection Thread Interrupted, url: " + jdbcUrl, e);
                    }
                    break;
                } finally {
                    lock.unlock();
                }

                PhysicalConnectionInfo connection = null;

                try {
                    connection = createPhysicalConnection();
                    setFailContinuous(false);
                } catch (SQLException e) {
                    LOG.error("create connection SQLException, url: " + jdbcUrl + ", errorCode " + e.getErrorCode()
                              + ", state " + e.getSQLState(), e);

                    errorCount++;
                    if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) {
                        // fail over retry attempts
                        setFailContinuous(true);
                        if (failFast) {
                            lock.lock();
                            try {
                                notEmpty.signalAll();
                            } finally {
                                lock.unlock();
                            }
                        }

                        if (breakAfterAcquireFailure) {
                            break;
                        }

                        try {
                            Thread.sleep(timeBetweenConnectErrorMillis);
                        } catch (InterruptedException interruptEx) {
                            break;
                        }
                    }
                } catch (RuntimeException e) {
                    LOG.error("create connection RuntimeException", e);
                    setFailContinuous(true);
                    continue;
                } catch (Error e) {
                    LOG.error("create connection Error", e);
                    setFailContinuous(true);
                    break;
                }

                if (connection == null) {
                    continue;
                }

                boolean result = put(connection);
                if (!result) {
                    JdbcUtils.close(connection.getPhysicalConnection());
                    LOG.info("put physical connection to pool failed.");
                }

                errorCount = 0; // reset errorCount
            }
        }
    }
ログイン後にコピー

これはマルチスレッド クラスであり、run メソッドには (;;) {} の無制限の for ループとログ エラーの場所情報があります:

connection = createPhysicalConnection();
ログイン後にコピー

If 条件は次のとおりです。 met errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0 will tr​​y to reconnect again. まずこれらのパラメータの意味を見てみましょう:

errorCount エラーの数

は、run メソッドが実行されたときは 0 です。接続が失敗するたびに、自動的に 1

connectionErrorRetryAttempts

接続エラーの再試行回数が増加します。デフォルト値は 1 です。

protected int  connectionErrorRetryAttempts  = 1;
ログイン後にコピー

timeBetweenConnectErrorMillis

接続間隔時間 (ミリ秒単位)。デフォルト値は 500 です。

protected volatile long timeBetweenConnectErrorMillis = DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS;
public static final long DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS = 500;
ログイン後にコピー

データベースへの接続に失敗した後、内部に侵入する必要があります。

if (breakAfterAcquireFailure) {
     break;
}
ログイン後にコピー

Break-after-acquire-failure を true に設定し、application.properties ファイルを次のように構成します。

spring.datasource.druid.break-after-acquire-failure=true
ログイン後にコピー

複数回接続を試みたい場合は、connection-error-retry-attempts を設定する必要があります。errorCount が connectionErrorRetryAttempts より大きい場合、条件に入り、ループが中断されます。 application.properties ファイルの構成は次のとおりです:

spring.datasource.druid.connection-error-retry-attempts=3
ログイン後にコピー

以上がspringboot druid データベース接続プールが接続失敗後に再接続し続ける問題を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:yisu.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート