Maison  >  Article  >  Java  >  Comment résoudre le problème selon lequel le pool de connexions à la base de données Springboot Druid continue de se reconnecter après un échec de connexion

Comment résoudre le problème selon lequel le pool de connexions à la base de données Springboot Druid continue de se reconnecter après un échec de connexion

王林
王林avant
2023-05-21 11:28:253111parcourir

Lorsque j'ai utilisé ma machine de test Alibaba Cloud personnelle, lors de la visualisation du journal de sortie en temps réel, j'ai constaté qu'après l'échec de la connexion à la base de données, le serveur essayait de se reconnecter. Au début, on pensait que le système était continuellement attaqué, mais après le redémarrage du service, la reconnexion constante n'a plus eu lieu. Regardez le journal de sortie suivant :

2022-02-09 11:04:58.896 ERREUR 16876 --- [eate-1550991149] com.alibaba.druid.pool.DruidDataSource : créer une connexion SQLException, url : jdbc:mysql : // 47.98.67,98:1234/test?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC, errorCode 1045, état 28000

java.sql.SQLException : accès refusé pour l'utilisateur 'root'@'113.90.123.76' (en utilisant mot de passe : OUI)
sur com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) ~[mysql-connector-java-8.0.16.jar:8.0.16]
sur com.mysql. cj. jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) ~[mysql-connector-java-8.0.16.jar:8.0.16]
sur com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException( SQLExceptionsMapping. java:122) ~[mysql-connector-java-8.0.16.jar:8.0.16]
sur com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:835) ~[mysql-connector- java- 8.0.16.jar:8.0.16]
sur com.mysql.cj.jdbc.ConnectionImpl.7e51f00a783d7eb8f68358439dee7daf(ConnectionImpl.java:455) ~[mysql-connector-java-8.0.16.jar:8.0 .16 ]
sur com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:240) ~[mysql-connector-java-8.0.16.jar:8.0.16]
sur com.mysql.cj.jdbc .NonRegisteringDriver .connect(NonRegisteringDriver.java:199) ~[mysql-connector-java-8.0.16.jar:8.0.16]
sur com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:156) ~ [druid -1.1.10.jar:1.1.10]
sur com.alibaba.druid.filter.stat.StatFilter.connection_connect(StatFilter.java:218) ~[druid-1.1.10.jar:1.1.10]
sur com .alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:150) ~[druid-1.1.10.jar:1.1.10]
sur com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java :1560) ~[druid-1.1.10.jar:1.1.10]
sur com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1623) ~[druid-1.1.10.jar:1.1.10 ]
sur com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2468) ~[druid-1.1.10.jar:1.1.10]

Notez qu'il y a toujours une invite pour le druide pool de connexion à la base de données ci-dessus, ici j'ai pensé que cela pourrait être un problème avec le pool de connexion du druide, puis après avoir supprimé la dépendance du druide maven, il n'y aura aucun problème de reconnexion dans l'interface de requête.

La raison de la reconnexion du druide

Recherchez la dernière ligne de DruidDataSource.java:2468 dans le code source ci-dessus. Accédez au code source. CreateConnectionThread crée un fil de connexion. Jetez un œil au code source de 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
            }
        }
    }

This. est une classe multithread, et dans la méthode d'exécution, une boucle for illimitée pour (;;) {} est configurée et les informations sur l'emplacement de l'erreur du journal sont :

connection = createPhysicalConnection();

Si les conditions sont remplies, errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > ; 0, la reconnexion sera tentée à nouveau. Jetez d'abord un œil à ces paramètres Signification :

errorCount Le nombre d'erreurs

est nul lorsque la méthode run est initialisée, chaque fois que la connexion échoue, elle ajoutera automatiquement 1

.

connectionErrorRetryAttempts

Le nombre de tentatives d'erreur de connexion, la valeur par défaut est 1.

protected int  connectionErrorRetryAttempts  = 1;

timeBetweenConnectErrorMillis

Intervalle de connexion en millisecondes. La valeur par défaut est 500.

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

Après avoir échoué à nous connecter à la base de données, nous devons entrer à l'intérieur,

if (breakAfterAcquireFailure) {
     break;
}

changera break-after-acquire-failure en true et le configurera comme suit dans le fichier application.properties :

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

Si vous souhaitez essayer de vous connecter plusieurs fois, les tentatives de nouvelle tentative d'erreur de connexion doivent être définies. Lorsque errorCount est supérieur à connectionErrorRetryAttempts, la condition sera entrée et la boucle sera interrompue. Voici la configuration du fichier application.properties :

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer