Maison > Java > javaDidacticiel > le corps du texte

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

王林
Libérer: 2023-05-21 11:28:25
avant
3183 Les gens l'ont consulté

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.(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
            }
        }
    }
Copier après la connexion

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();
Copier après la connexion

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;
Copier après la connexion

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;
Copier après la connexion

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

if (breakAfterAcquireFailure) {
     break;
}
Copier après la connexion

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
Copier après la connexion
.

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
Copier après la connexion

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!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal