개인 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 종속성을 제거한 후에는 요청 인터페이스에 다시 연결 문제가 없을 것입니다.
위 소스 코드에서 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이면 다시 연결이 시도됩니다. 의미:
이 추가됩니다.
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 중국어 웹사이트의 기타 관련 기사를 참조하세요!