diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index 4899b6921b..67ce0638d7 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -635,7 +635,7 @@ public abstract class DruidAbstractDataSource implements DataSource, DataSourceP } } - public void validateConnection(Connection conn) throws SQLException { + protected void validateConnection(Connection conn) throws SQLException { String query = getValidationQuery(); if (conn.isClosed()) { throw new SQLException("validateConnection: connection closed"); diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 25c0cee41f..b84aff1329 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -124,7 +124,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat this.driverClass = driver.getClass().getName(); } } - + this.dbType = JdbcUtils.getDbType(jdbcUrl, driverClass.getClass().getName()); for (Filter filter : filters) { @@ -191,6 +191,23 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } + for (;;) { + PoolableConnection poolalbeConnection = getConnectionInternal(); + + if (isTestOnBorrow()) { + boolean validate = testConnection(poolalbeConnection.getRawConnection()); + if (!validate) { + continue; + } + } + + return poolalbeConnection; + } + } + + private PoolableConnection getConnectionInternal() throws SQLException { + PoolableConnection poolalbeConnection; + try { lock.lockInterruptibly(); @@ -208,27 +225,18 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat throw new SQLException("can not get connection"); } - if (isTestOnBorrow()) { - boolean validate = testConnection(holder.getConnection()); - if (!validate) { - continue; - } - } - break; } holder.incrementUseCount(); activeCount++; - PoolableConnection poolalbeConnection = new PoolableConnection(holder); + poolalbeConnection = new PoolableConnection(holder); if (activeConnectionTraceEnable) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); activeConnections.put(poolalbeConnection, new ActiveConnectionTraceInfo(poolalbeConnection, System.currentTimeMillis(), stackTrace)); } - - return poolalbeConnection; } catch (InterruptedException e) { connectErrorCount++; throw new SQLException(e.getMessage(), e); @@ -238,6 +246,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } finally { lock.unlock(); } + return poolalbeConnection; } /** @@ -511,7 +520,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat break; } catch (SQLException e) { printStackTrace(e); - + if (timeBetweenConnectErrorMillis > 0) { try { Thread.sleep(timeBetweenConnectErrorMillis); diff --git a/src/test/java/com/alibaba/druid/pool/benckmark/Case1.java b/src/test/java/com/alibaba/druid/pool/benckmark/Case1.java index 508bae1a6d..43013190a8 100644 --- a/src/test/java/com/alibaba/druid/pool/benckmark/Case1.java +++ b/src/test/java/com/alibaba/druid/pool/benckmark/Case1.java @@ -29,6 +29,11 @@ import com.alibaba.druid.TestUtil; import com.alibaba.druid.pool.DruidDataSource; import com.jolbox.bonecp.BoneCPDataSource; +/** + * TestOnBo + * 类Case1.java的实现描述:TODO 类实现描述 + * @author admin 2011-5-28 下午03:47:40 + */ public class Case1 extends TestCase { private String jdbcUrl; diff --git a/src/test/java/com/alibaba/druid/pool/benckmark/Case2.java b/src/test/java/com/alibaba/druid/pool/benckmark/Case2.java new file mode 100644 index 0000000000..6f34399c59 --- /dev/null +++ b/src/test/java/com/alibaba/druid/pool/benckmark/Case2.java @@ -0,0 +1,165 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.pool.benckmark; + +import java.sql.Connection; +import java.text.NumberFormat; +import java.util.concurrent.CountDownLatch; + +import javax.sql.DataSource; + +import junit.framework.TestCase; + +import org.apache.commons.dbcp.BasicDataSource; + +import com.alibaba.druid.TestUtil; +import com.alibaba.druid.pool.DruidDataSource; +import com.jolbox.bonecp.BoneCPDataSource; + +/** + * TestOnBo + * 类Case1.java的实现描述:TODO 类实现描述 + * @author admin 2011-5-28 下午03:47:40 + */ +public class Case2 extends TestCase { + + private String jdbcUrl; + private String user; + private String password; + private String driverClass; + private int initialSize = 10; + private int minPoolSize = 1; + private int maxPoolSize = 2; + private int maxActive = 2; + private String validationQuery = "SELECT 1"; + private int threadCount = 1; + private int loopCount = 5; + final int LOOP_COUNT = 1000 * 1000; + private boolean testOnBorrow = true; + + protected void setUp() throws Exception { + jdbcUrl = "jdbc:fake:dragoon_v25masterdb"; + user = "dragoon25"; + password = "dragoon25"; + driverClass = "com.alibaba.druid.mock.MockDriver"; + } + + public void test_0() throws Exception { + DruidDataSource dataSource = new DruidDataSource(); + + dataSource.setInitialSize(initialSize); + dataSource.setMaxActive(maxActive); + dataSource.setMinIdle(minPoolSize); + dataSource.setMaxIdle(maxPoolSize); + dataSource.setPoolPreparedStatements(true); + dataSource.setDriverClassName(driverClass); + dataSource.setUrl(jdbcUrl); + dataSource.setPoolPreparedStatements(true); + dataSource.setUsername(user); + dataSource.setPassword(password); + dataSource.setValidationQuery(validationQuery); + dataSource.setTestOnBorrow(testOnBorrow); + + for (int i = 0; i < loopCount; ++i) { + p0(dataSource, "druid", threadCount); + } + System.out.println(); + } + + public void test_1() throws Exception { + final BasicDataSource dataSource = new BasicDataSource(); + + dataSource.setInitialSize(initialSize); + dataSource.setMaxActive(maxActive); + dataSource.setMinIdle(minPoolSize); + dataSource.setMaxIdle(maxPoolSize); + dataSource.setPoolPreparedStatements(true); + dataSource.setDriverClassName(driverClass); + dataSource.setUrl(jdbcUrl); + dataSource.setPoolPreparedStatements(true); + dataSource.setUsername(user); + dataSource.setPassword(password); + dataSource.setValidationQuery("SELECT 1"); + dataSource.setTestOnBorrow(testOnBorrow); + + for (int i = 0; i < loopCount; ++i) { + p0(dataSource, "dbcp", threadCount); + } + System.out.println(); + } + + // 当testOnBorrow为true时,BoneCP的处理策略不一样,所以略过 + public void f_test_2() throws Exception { + BoneCPDataSource dataSource = new BoneCPDataSource(); + // dataSource.(10); + // dataSource.setMaxActive(50); + dataSource.setMinConnectionsPerPartition(minPoolSize); + dataSource.setMaxConnectionsPerPartition(maxPoolSize); + + dataSource.setDriverClass(driverClass); + dataSource.setJdbcUrl(jdbcUrl); + dataSource.setStatementsCacheSize(100); + // dataSource.setMaxOpenPreparedStatements(100); + dataSource.setUsername(user); + dataSource.setPassword(password); + dataSource.setConnectionTestStatement("SELECT 1"); + dataSource.setPartitionCount(1); + dataSource.setAcquireIncrement(5); + dataSource.setIdleConnectionTestPeriod(0L); + // dataSource.setDisableConnectionTracking(true); + + for (int i = 0; i < loopCount; ++i) { + p0(dataSource, "boneCP", threadCount); + } + System.out.println(); + } + + private void p0(final DataSource dataSource, String name, int threadCount) throws Exception { + + final CountDownLatch startLatch = new CountDownLatch(1); + final CountDownLatch endLatch = new CountDownLatch(1); + for (int i = 0; i < threadCount; ++i) { + Thread thread = new Thread() { + + public void run() { + try { + startLatch.await(); + + for (int i = 0; i < LOOP_COUNT; ++i) { + Connection conn = dataSource.getConnection(); + conn.close(); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + endLatch.countDown(); + } + }; + thread.start(); + } + long startMillis = System.currentTimeMillis(); + long startYGC = TestUtil.getYoungGC(); + long startFullGC = TestUtil.getFullGC(); + startLatch.countDown(); + endLatch.await(); + + long millis = System.currentTimeMillis() - startMillis; + long ygc = TestUtil.getYoungGC() - startYGC; + long fullGC = TestUtil.getFullGC() - startFullGC; + + System.out.println("thread " + threadCount + " " + name + " millis : " + NumberFormat.getInstance().format(millis) + ", YGC " + ygc + " FGC " + fullGC); + } +}