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