Heim >Java >javaLernprogramm >So lösen Sie das Problem, dass der Springboot-Druiden-Datenbankverbindungspool nach einem Verbindungsfehler immer wieder eine Verbindung herstellt

So lösen Sie das Problem, dass der Springboot-Druiden-Datenbankverbindungspool nach einem Verbindungsfehler immer wieder eine Verbindung herstellt

王林
王林nach vorne
2023-05-21 11:28:253238Durchsuche

Als ich meine persönliche Alibaba Cloud-Testmaschine verwendete und das Echtzeit-Ausgabeprotokoll ansah, stellte ich fest, dass der Server nach dem Ausfall der Datenbankverbindung immer wieder versuchte, die Verbindung wiederherzustellen. Zunächst ging man davon aus, dass das System ständig angegriffen wurde, doch nach dem Neustart des Dienstes kam es nicht mehr zu einer ständigen Neuverbindung. Sehen Sie sich das folgende Ausgabeprotokoll an:

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: Zugriff verweigert für Benutzer 'root'@'113.90.123.76' (using Passwort: JA)
bei com.mysql.cj.jdbc.Exceptions.SQLError.createSQLException(SQLError.java:129) ~[mysql-connector-java-8.0.16.jar:8.0.16]
bei com.mysql. cj.jdbc.Exceptions.SQLError.createSQLException(SQLError.java:97) ~[mysql-connector-java-8.0.16.jar:8.0.16]
bei com.mysql.cj.jdbc.Exceptions.SQLExceptionsMapping.translateException( SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.16.jar:8.0.16]
bei com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:835) ~[mysql-connector- java- 8.0.16.jar:8.0.16]
unter com.mysql.cj.jdbc.ConnectionImpl.7e51f00a783d7eb8f68358439dee7daf(ConnectionImpl.java:455) ~[mysql-connector-java-8.0.16.jar:8.0 .16 ]
bei com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:240) ~[mysql-connector-java-8.0.16.jar:8.0.16]
bei com.mysql.cj.jdbc .NonRegisteringDriver .connect(NonRegisteringDriver.java:199) ~[mysql-connector-java-8.0.16.jar:8.0.16]
bei com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:156) ~ [druid -1.1.10.jar:1.1.10]
unter com.alibaba.druid.filter.stat.StatFilter.connection_connect(StatFilter.java:218) ~[druid-1.1.10.jar:1.1.10]
unter com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:150) ~[druid-1.1.10.jar:1.1.10]
unter com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java :1560 ) ~[druid-1.1.10.jar:1.1.10]
bei com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1623) ~[druid-1.1.10.jar:1.1.10 ]
unter com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2468) ~[druid-1.1.10.jar:1.1.10]

Beachten Sie, dass es immer eine Eingabeaufforderung für den Druiden gibt Datenbankverbindungspool oben, hier dachte ich, es könnte ein Problem mit dem Druiden-Verbindungspool sein, und nach dem Entfernen der Druiden-Maven-Abhängigkeit wird es in der Anforderungsschnittstelle kein Problem mit der erneuten Verbindung geben.

Der Grund für die Druid-Wiederverbindung

Suchen Sie die letzte Zeile von DruidDataSource.java:2468 im Quellcode. Navigieren Sie zum Quellcode von 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
            }
        }
    }
ist eine Multithread-Klasse und in der Ausführungsmethode wird eine unbegrenzte for-Schleife für (;;) {} eingerichtet, und die Informationen zum Protokollfehlerort lauten:

connection = createPhysicalConnection();

Wenn die Bedingungen erfüllt sind, errorCount > ConnectionErrorRetryAttempts && timeBetweenConnectErrorMillis > ; 0, die erneute Verbindung wird erneut versucht. Bedeutung:

errorCount Die Anzahl der Fehler

ist Null, wenn die Verbindung fehlschlägt

connectionErrorRetryAttempts

Die Anzahl der Verbindungsfehler-Wiederholungsversuche, der Standardwert ist 1.

protected int  connectionErrorRetryAttempts  = 1;

timeBetweenConnectErrorMillis

Verbindungsintervallzeit in Millisekunden. Der Standardwert ist 500.

protected volatile long timeBetweenConnectErrorMillis = DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS;
public static final long DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS = 500;

Nachdem wir keine Verbindung zur Datenbank herstellen konnten, müssen wir einbrechen. Unter anderem ändert

if (breakAfterAcquireFailure) {
     break;
}

„break-after-acquire-failure“ in „true“ und konfiguriert es wie folgt in der Datei „application.properties“:

spring.datasource.druid.break-after-acquire-failure=true

Wenn Sie mehrmals versuchen möchten, eine Verbindung herzustellen, müssen „connection-error-retry-attempts“ festgelegt werden. Wenn „errorCount“ größer als „connectionErrorRetryAttempts“ ist, wird die Bedingung eingegeben und die Schleife unterbrochen. Das Folgende ist die Konfiguration der application.properties-Datei:

spring.datasource.druid.connection-error-retry-attempts=3

Das obige ist der detaillierte Inhalt vonSo lösen Sie das Problem, dass der Springboot-Druiden-Datenbankverbindungspool nach einem Verbindungsfehler immer wieder eine Verbindung herstellt. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen