>Java >java지도 시간 >springboot druid 데이터베이스 연결 풀이 연결 실패 후 계속 다시 연결되는 문제를 해결하는 방법

springboot druid 데이터베이스 연결 풀이 연결 실패 후 계속 다시 연결되는 문제를 해결하는 방법

王林
王林앞으로
2023-05-21 11:28:253240검색

개인 Alibaba Cloud 테스트 머신을 사용했을 때 실시간 출력 로그를 볼 때 데이터베이스 연결이 실패한 후 서버가 계속 재연결을 시도하는 것을 발견했습니다. 처음에는 시스템이 지속적인 공격을 받고 있는 줄 알았으나, 서비스를 다시 시작한 이후에는 더 이상 지속적인 재접속이 발생하지 않았습니다. 다음 출력 로그를 살펴보십시오.

2022-02-09 11:04:58.896 ERROR 16876 --- [eate-1550991149] com.alibaba.druid.pool.DruidDataSource : 연결 생성 SQLException, url: jdbc:mysql: // 47.98.67,98:1234/test?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC, errorCode 1045, 상태 28000

java.sql.SQLException: 'root'@'113.90.123.76' 사용자에 대한 액세스가 거부되었습니다(사용 비밀번호: YES)
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]
com.mysql.cj.jdbc.ConnectionImpl.7e51f00a783d7eb8f68358439dee7daf(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 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();

조건이 충족되면 errorCount > 0이면 다시 연결이 시도됩니다. 의미:

errorCount 연결이 실패할 때마다 자동으로 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

더 여러 번 연결을 시도하려면 연결 오류-재시도를 설정해야 합니다. errorCount가 연결 오류RetryAttempts보다 크면 조건이 입력되고 루프가 중단됩니다. 다음은 application.properties 파일의 구성입니다.

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

위 내용은 springboot druid 데이터베이스 연결 풀이 연결 실패 후 계속 다시 연결되는 문제를 해결하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제