druid 連接失敗不停嘗試重連的解決方案。


看一段druid創建連接的源碼:

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 (;;) {
                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.get() < initialSize) {
                        emptyWait = false;
                    }

                    if (emptyWait) {
                        if (poolingCount >= notEmptyWaitThreadCount //
                                && !(keepAlive && activeCount + poolingCount < minIdle)) {
                            empty.await();
                        }

                        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) {
                        setFailContinuous(true);
                        if (failFast) {
                            lock.lock();
                            try {
                                notEmpty.signalAll();
                            } finally {
                                lock.unlock();
                            }
                        }

                        //(1)如果獲取失敗跳出
                        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;
                }

                // (2)未獲取到連接繼續
                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
            }
        }
    }

以上兩個注釋處,有兩個關鍵點:

  • 注釋(2)處,如果獲取失敗(connection == null),則繼續獲取。這里是不停嘗試重連的原因所在。
  • 注釋(1)處,如果獲取失敗,則放棄獲取直接跳出。

所以容易看出,只要給(1)處的 breakAfterAcquireFailure 置為true,就可以解決問題, 然而,druid的配置項中並沒有這個選項,但我們發現,DruidDataSource提供了setBreakAfterAcquireFailure(boolean)方法。

再看一段通常我們創建數據源會寫的代碼:

Properties p =new Properties();
p.put("url", url);
p.put("username", username);
p.put("password", password);
DataSource dataSource = DruidDataSourceFactory.createDataSource(p);

DruidDataSourceFactory.createDataSource() 方法內部實現:

.....// 這里省略了很多的讀取一些properteis配置的代碼
value = (String) properties.get(“init”);
if ("true".equals(value)) {
    dataSource.init();
}
            

注意看,這里,通過讀取init配置項來判斷是否要初始化數據源。而我們現在要做的是:將breakAfterAcquireFailure 置為true,而配置項中不存在,所以我們需要將init設置為false,然后手動setBreakAfterAcquireFailure(true),然后手動init數據源。所以有以下方案:

public DataSource build(String url, String username, String password) throws Exception {
     Properties p =new Properties();
     p.put("init","false");
     p.put("url", url);
     p.put("username", username);
     p.put("password", password);
     DruidDataSource dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(p);
     dataSource.setBreakAfterAcquireFailure(true);
     dataSource.init();
     return dataSource;
}

通過構建完的DataSource替換系統中的datasource生成即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM