When using the personal Ali Cloud test machine, I found that the server had been reconnecting to the server after the database connection failed when I queried the real-time output log. At first, I thought it was a repeat attack, but after the service was restarted, there was no continuous reconnection. Look at the following output log:

The 2022-02-09 11:04:58. ERROR 896-16876 [eate - 1550991149] com. Alibaba. Druid. Pool. DruidDataSource: The 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: Access denied for user 'root'@'113.90.123.76' (using password: YES) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) ~ [mysql connector - Java - 8.0.16 jar: 8.0.16] at the mysql. Cj. JDBC. Exceptions. SQLError. CreateSQLException (SQLError. Java: 97) ~ [mysql connector - Java - 8.0.16 jar: 8.0.16] the at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~ [mysql connector - Java - 8.0.16 jar: 8.0.16] at the mysql. Cj. JDBC. ConnectionImpl. CreateNewIO (ConnectionImpl. Java: 835) ~ [mysql connector - Java - 8.0.16 jar: 8.0.16] at the mysql. Cj. JDBC. ConnectionImpl. < init > (ConnectionImpl. Java: 455) ~ [mysql connector - Java - 8.0.16 jar: 8.0.16] at the mysql. Cj. JDBC. ConnectionImpl. GetInstance (ConnectionImpl. Java: 240) ~ [mysql connector - Java - 8.0.16 jar: 8.0.16] the at Com. Mysql. Cj. JDBC. NonRegisteringDriver. Connect (NonRegisteringDriver. Java: 199) ~ [mysql connector - Java - 8.0.16. Jar: 8.0.16] At com. Alibaba. Druid. Filter. FilterChainImpl. Connection_connect (FilterChainImpl. Java: 156) ~ [druid - 1.1.10. Jar: 1.1.10] the at Com. Alibaba. Druid. Filter. Stat. StatFilter. Connection_connect (StatFilter. Java: 218) ~ / druid - 1.1.10. Jar: 1.1.10 ats Com. Alibaba. Druid. Filter. FilterChainImpl. Connection_connect (FilterChainImpl. Java: 150) ~ / druid - 1.1.10. Jar: 1.1.10 ats com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1560) ~ [druid - 1.1.10 jar: 1.1.10] the at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1623) ~ [druid - 1.1.10 jar: 1.1.10] the at Com. Alibaba. Druid. Pool. DruidDataSource $CreateConnectionThread. Run (DruidDataSource. Java: 2468) ~ [druid - 1.1.10. Jar: 1.1.10]Copy the code

Note that the above has been druid database connection pool, here thought that could be a druid connection pool, and then remove the druid maven dependencies won’t appear in request interface reconnection.

Druid Reconnection cause

Source to find the last line of the chart above DruidDataSource. Java: 2468 positioning to the source, CreateConnectionThread create connection thread, look at the CreateConnectionThread source code:

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(); } // Prevent the creation of more connections than maxActive if (activeCount + poolingCount >= maxActive) {empt.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 } } }Copy the code

This is a multithreaded class, and the run method has an unlimited for loop for (;;). {}, and the log reports error location information:

connection = createPhysicalConnection();
Copy the code

If eligible errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0 will try again to reconnection, first look at the meaning of several parameters:

ErrorCount Number of errors

Zero when the run method is initialized, and automatically increments by 1 each time a connection fails

connectionErrorRetryAttempts

Number of connection error retries. Default value: 1.

protected int  connectionErrorRetryAttempts  = 1;
Copy the code

timeBetweenConnectErrorMillis

Connection interval, in milliseconds. The default value is 500.

protected volatile long timeBetweenConnectErrorMillis = DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS;
public static final long DEFAULT_TIME_BETWEEN_CONNECT_ERROR_MILLIS = 500;
Copy the code

We failed to connect to the database, or break inside, where there is

if (breakAfterAcquireFailure) {
     break;
}
Copy the code

Set break-after-acquire-failure to true and configure the following in the application.properties file:

spring.datasource.druid.break-after-acquire-failure=true
Copy the code

If you want to try to connect a few times more, you need to set up the connection – error – retry attempts, when errorCount than connectionErrorRetryAttempts will enter the condition, the loop will interrupt. In the application.properties file:

spring.datasource.druid.connection-error-retry-attempts=3
Copy the code

conclusion

Druid database connection failed due to unbounded loop connection while using multithreaded connection data, break connection when connection failed and set break-after-acquire-failure to true. If the database connection fails, it will not retry continuously. To set the retry times, set the connection-erry-retry-attempts. If you find this article helpful, please give it a thumbs up!