diff --git a/CHANGES b/CHANGES
index 556730a9..08b71b1f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,40 @@
HikariCP Changes
+Changes between 1.3.3 and 1.3.4
+
+ *) Added new property isolateInternalQueries used to control whether
+ internal pool queries such as connection alive tests are isolated
+ in their own transaction.
+
+ *) Added properties for DriverManager (driverClassName) and JDBC URL-based
+ (jdbcUrl) configuration. 1999 called and wants its JDBC driver back.
+
+ *) Added new username and password properties to allow default authentication
+ for connections.
+
+ *) Added support for the getConnection(username, password) method signature
+ to HikariDataSource.
+
+ *) Added new property readOnly to control the default read-only status
+ of connections in the pool.
+
+ *) Deprecated acquireIncrement property.
+
+ *) Deprecated acquireRetries property.
+
+ *) Deprecated acquireRetryDelay property.
+
+ *) Deprecated minimumPoolSize property.
+
+ *) Added new property minimumIdle used to control the minimum number of
+ idle connections the pool should try to maintain on a running basis.
+
+ *) Added evictConnection(Connection) method to HikariDataSource to allow
+ special cases where users wish to forcibly eject a connection from
+ the pool. To use used cautiously, read the JavaDoc before using.
+
+ *) Various bug fixes and minor enhancements.
+
Changes between 1.3.2 and 1.3.3
*) Removed shared state contention that was causing excessive CPU cache-line
diff --git a/pom.xml b/pom.xml
index 68b09487..f53df426 100644
--- a/pom.xml
+++ b/pom.xml
@@ -83,6 +83,12 @@
4.3.0.Final
provided
+
+ com.codahale.metrics
+ metrics-core
+ 3.0.2
+ provided
+
@@ -148,7 +154,7 @@
HikariCP
com.zaxxer.hikari
- com.sun.tools.attach,javassist.*,
+ javassist.*,
javax.management,
javax.sql,
javax.sql.rowset,
@@ -199,7 +205,7 @@
2.9.1
public
- com.zaxxer.hikari.*
+
true
1024m
diff --git a/src/main/java/com/zaxxer/hikari/HikariConfig.java b/src/main/java/com/zaxxer/hikari/HikariConfig.java
index b063be73..ca14d7c7 100644
--- a/src/main/java/com/zaxxer/hikari/HikariConfig.java
+++ b/src/main/java/com/zaxxer/hikari/HikariConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Brett Wooldridge
+ * Copyright (C) 2013, 2014 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@ public class HikariConfig implements HikariConfigMBean
{
private static final Logger LOGGER = LoggerFactory.getLogger(HikariConfig.class);
- private static final long CONNECTION_TIMEOUT = 5000L;
+ private static final long CONNECTION_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
private static final long IDLE_TIMEOUT = TimeUnit.MINUTES.toMillis(10);
private static final long MAX_LIFETIME = TimeUnit.MINUTES.toMillis(30);
@@ -45,26 +45,32 @@ public class HikariConfig implements HikariConfigMBean
// Properties changeable at runtime through the MBean
//
- private volatile int acquireRetries;
private volatile long connectionTimeout;
private volatile long idleTimeout;
private volatile long leakDetectionThreshold;
private volatile long maxLifetime;
private volatile int maxPoolSize;
- private volatile int minPoolSize;
+ private volatile int minIdle;
// Properties NOT changeable at runtime
//
- private String transactionIsolationName;
+ private String catalog;
private String connectionCustomizerClassName;
private String connectionInitSql;
private String connectionTestQuery;
private String dataSourceClassName;
- private String catalog;
+ private String driverClassName;
+ private String jdbcUrl;
+ private String password;
private String poolName;
+ private String transactionIsolationName;
+ private String username;
private boolean isAutoCommit;
+ private boolean isReadOnly;
private boolean isInitializationFailFast;
private boolean isJdbc4connectionTest;
+ private boolean isIsolateInternalQueries;
+ private boolean isRecordMetrics;
private boolean isRegisterMbeans;
private DataSource dataSource;
private Properties dataSourceProperties;
@@ -83,15 +89,15 @@ public class HikariConfig implements HikariConfigMBean
{
dataSourceProperties = new Properties();
- acquireRetries = 3;
connectionTimeout = CONNECTION_TIMEOUT;
idleTimeout = IDLE_TIMEOUT;
isAutoCommit = true;
isJdbc4connectionTest = true;
- minPoolSize = 10;
- maxPoolSize = 60;
+ minIdle = -1;
+ maxPoolSize = 10;
maxLifetime = MAX_LIFETIME;
poolName = "HikariPool-" + poolNumber++;
+ isRecordMetrics = false;
transactionIsolation = -1;
}
@@ -136,89 +142,122 @@ public class HikariConfig implements HikariConfigMBean
}
}
- public int getAcquireIncrement()
- {
- return 0;
- }
-
+ @Deprecated
public void setAcquireIncrement(int acquireIncrement)
{
LOGGER.warn("The acquireIncrement property has been retired, remove it from your pool configuration to avoid this warning.");
}
/** {@inheritDoc} */
- public int getAcquireRetries()
- {
- return acquireRetries;
- }
-
- /** {@inheritDoc} */
+ @Deprecated
public void setAcquireRetries(int acquireRetries)
{
- if (acquireRetries < 0)
- {
- throw new IllegalArgumentException("acquireRetries cannot be negative");
- }
- this.acquireRetries = acquireRetries;
- }
-
- public long getAcquireRetryDelay()
- {
- return 0;
+ LOGGER.warn("The acquireRetries property has been retired, remove it from your pool configuration to avoid this warning.");
}
+ @Deprecated
public void setAcquireRetryDelay(long acquireRetryDelayMs)
{
LOGGER.warn("The acquireRetryDelay property has been retired, remove it from your pool configuration to avoid this warning.");
}
+ /**
+ * Get the default catalog name to be set on connections.
+ *
+ * @return the default catalog name
+ */
public String getCatalog()
{
return catalog;
}
+ /**
+ * Set the default catalog name to be set on connections.
+ *
+ * @param catalog the catalog name, or null
+ */
public void setCatalog(String catalog)
{
this.catalog = catalog;
}
+ /**
+ * Get the name of the connection customizer class to instantiate and execute
+ * on all new connections.
+ *
+ * @return the name of the customizer class, or null
+ */
public String getConnectionCustomizerClassName()
{
return connectionCustomizerClassName;
}
+ /**
+ * Set the name of the connection customizer class to instantiate and execute
+ * on all new connections.
+ *
+ * @param connectionCustomizerClassName the name of the customizer class
+ */
public void setConnectionCustomizerClassName(String connectionCustomizerClassName)
{
this.connectionCustomizerClassName = connectionCustomizerClassName;
}
+ /**
+ * Get the SQL query to be executed to test the validity of connections.
+ *
+ * @return the SQL query string, or null
+ */
public String getConnectionTestQuery()
{
return connectionTestQuery;
}
+ /**
+ * Set the SQL query to be executed to test the validity of connections. Using
+ * the JDBC4 {@link Connection.isValid()} method to test connection validity can
+ * be more efficient on some databases and is recommended. See
+ * {@link HikariConfig#setJdbc4ConnectionTest(boolean)}.
+ *
+ * @param connectionTestQuery a SQL query string
+ */
public void setConnectionTestQuery(String connectionTestQuery)
{
this.connectionTestQuery = connectionTestQuery;
}
+ /**
+ * Get the SQL string that will be executed on all new connections when they are
+ * created, before they are added to the pool.
+ *
+ * @return the SQL to execute on new connections, or null
+ */
public String getConnectionInitSql()
{
return connectionInitSql;
}
+ /**
+ * Set the SQL string that will be executed on all new connections when they are
+ * created, before they are added to the pool. If this query fails, it will be
+ * treated as a failed connection attempt.
+ *
+ * @param connectionInitSql the SQL to execute on new connections
+ */
public void setConnectionInitSql(String connectionInitSql)
{
this.connectionInitSql = connectionInitSql;
}
/** {@inheritDoc} */
+ @Override
public long getConnectionTimeout()
{
return connectionTimeout;
}
/** {@inheritDoc} */
+ @Override
public void setConnectionTimeout(long connectionTimeoutMs)
{
if (connectionTimeoutMs == 0)
@@ -235,11 +274,23 @@ public class HikariConfig implements HikariConfigMBean
}
}
+ /**
+ * Get the {@link DataSource} that has been explicitly specified to be wrapped by the
+ * pool.
+ *
+ * @return the {@link DataSource} instance, or null
+ */
public DataSource getDataSource()
{
return dataSource;
}
+ /**
+ * Set a {@link DataSource} for the pool to explicitly wrap. This setter is not
+ * available through property file based initialization.
+ *
+ * @param dataSource a specific {@link DataSource} to be wrapped by the pool
+ */
public void setDataSource(DataSource dataSource)
{
this.dataSource = dataSource;
@@ -270,38 +321,96 @@ public class HikariConfig implements HikariConfigMBean
dataSourceProperties.putAll(dsProperties);
}
+ public void setDriverClassName(String driverClassName)
+ {
+ try
+ {
+ Class> driverClass = this.getClass().getClassLoader().loadClass(driverClassName);
+ driverClass.newInstance();
+ this.driverClassName = driverClassName;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("driverClassName specified class '" + driverClassName + "' could not be loaded", e);
+ }
+ }
+
/** {@inheritDoc} */
+ @Override
public long getIdleTimeout()
{
return idleTimeout;
}
/** {@inheritDoc} */
+ @Override
public void setIdleTimeout(long idleTimeoutMs)
{
this.idleTimeout = idleTimeoutMs;
}
+ public String getJdbcUrl()
+ {
+ return jdbcUrl;
+ }
+
+ public void setJdbcUrl(String jdbcUrl)
+ {
+ this.jdbcUrl = jdbcUrl;
+ }
+
+ /**
+ * Get the default auto-commit behavior of connections in the pool.
+ *
+ * @return the default auto-commit behavior of connections
+ */
public boolean isAutoCommit()
{
return isAutoCommit;
}
+ /**
+ * Set the default auto-commit behavior of connections in the pool.
+ *
+ * @param isAutoCommit the desired auto-commit default for connections
+ */
public void setAutoCommit(boolean isAutoCommit)
{
this.isAutoCommit = isAutoCommit;
}
+ /**
+ * Get whether or not the construction of the pool should throw an exception
+ * if the minimum number of connections cannot be created.
+ *
+ * @return whether or not initialization should fail on error immediately
+ */
public boolean isInitializationFailFast()
{
return isInitializationFailFast;
}
+ /**
+ * Set whether or not the construction of the pool should throw an exception
+ * if the minimum number of connections cannot be created.
+ *
+ * @param failFast true if the pool should fail if the minimum connections cannot be created
+ */
public void setInitializationFailFast(boolean failFast)
{
isInitializationFailFast = failFast;
}
+ public boolean isIsolateInternalQueries()
+ {
+ return isIsolateInternalQueries;
+ }
+
+ public void setIsolateInternalQueries(boolean isolate)
+ {
+ this.isIsolateInternalQueries = isolate;
+ }
+
public boolean isJdbc4ConnectionTest()
{
return isJdbc4connectionTest;
@@ -312,6 +421,31 @@ public class HikariConfig implements HikariConfigMBean
this.isJdbc4connectionTest = useIsValid;
}
+ public boolean isReadOnly()
+ {
+ return isReadOnly;
+ }
+
+ public void setReadOnly(boolean readOnly)
+ {
+ this.isReadOnly = readOnly;
+ }
+
+ public boolean isRecordMetrics()
+ {
+ return isRecordMetrics;
+ }
+
+ /**
+ * Currently not supported.
+ * @param recordMetrics
+ */
+ @Deprecated
+ public void setRecordMetrics(boolean recordMetrics)
+ {
+ this.isRecordMetrics = recordMetrics;
+ }
+
public boolean isRegisterMbeans()
{
return isRegisterMbeans;
@@ -323,57 +457,54 @@ public class HikariConfig implements HikariConfigMBean
}
/** {@inheritDoc} */
+ @Override
public long getLeakDetectionThreshold()
{
return leakDetectionThreshold;
}
/** {@inheritDoc} */
+ @Override
public void setLeakDetectionThreshold(long leakDetectionThresholdMs)
{
this.leakDetectionThreshold = leakDetectionThresholdMs;
}
+ @Deprecated
public void setUseInstrumentation(boolean useInstrumentation)
{
- // no longer used as of HikariCP 1.2.5
+ LOGGER.warn("The useInstrumentation property has been retired, remove it from your pool configuration to avoid this warning.");
}
/** {@inheritDoc} */
+ @Override
public long getMaxLifetime()
{
return maxLifetime;
}
/** {@inheritDoc} */
+ @Override
public void setMaxLifetime(long maxLifetimeMs)
{
this.maxLifetime = maxLifetimeMs;
}
- /** {@inheritDoc} */
- public int getMinimumPoolSize()
- {
- return minPoolSize;
- }
-
- /** {@inheritDoc} */
+ @Deprecated
public void setMinimumPoolSize(int minPoolSize)
{
- if (minPoolSize < 0)
- {
- throw new IllegalArgumentException("minPoolSize cannot be negative");
- }
- this.minPoolSize = minPoolSize;
+ LOGGER.warn("The minimumPoolSize property has been retired, remove it from your pool configuration to avoid this warning.");
}
/** {@inheritDoc} */
+ @Override
public int getMaximumPoolSize()
{
return maxPoolSize;
}
/** {@inheritDoc} */
+ @Override
public void setMaximumPoolSize(int maxPoolSize)
{
if (maxPoolSize < 0)
@@ -384,6 +515,43 @@ public class HikariConfig implements HikariConfigMBean
}
/** {@inheritDoc} */
+ @Override
+ public int getMinimumIdle()
+ {
+ return minIdle;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setMinimumIdle(int minIdle)
+ {
+ if (minIdle < 0 || minIdle > maxPoolSize)
+ {
+ throw new IllegalArgumentException("maxPoolSize cannot be negative or greater than maximumPoolSize");
+ }
+ this.minIdle = minIdle;
+ }
+
+ /**
+ * Get the default password to use for DataSource.getConnection(username, password) calls.
+ * @return the password
+ */
+ public String getPassword()
+ {
+ return password;
+ }
+
+ /**
+ * Set the default password to use for DataSource.getConnection(username, password) calls.
+ * @param password the password
+ */
+ public void setPassword(String password)
+ {
+ this.password = password;
+ }
+
+ /** {@inheritDoc} */
+ @Override
public String getPoolName()
{
return poolName;
@@ -417,10 +585,32 @@ public class HikariConfig implements HikariConfigMBean
this.transactionIsolationName = isolationLevel;
}
+ /**
+ * Get the default username used for DataSource.getConnection(username, password) calls.
+ *
+ * @return the username
+ */
+ public String getUsername()
+ {
+ return username;
+ }
+
+ /**
+ * Set the default username used for DataSource.getConnection(username, password) calls.
+ *
+ * @param username the username
+ */
+ public void setUsername(String username)
+ {
+ this.username = username;
+ }
+
public void validate()
{
Logger logger = LoggerFactory.getLogger(getClass());
+ validateNumerics();
+
if (connectionCustomizerClassName != null && connectionCustomizer == null)
{
try
@@ -435,79 +625,101 @@ public class HikariConfig implements HikariConfigMBean
}
}
- if (connectionTimeout == Integer.MAX_VALUE)
+ if (driverClassName != null && jdbcUrl == null)
{
- logger.warn("No connection wait timeout is set, this might cause an infinite wait.");
+ logger.error("when specifying driverClassName, jdbcUrl must also be specified");
+ throw new IllegalStateException("when specifying driverClassName, jdbcUrl must also be specified");
}
- else if (connectionTimeout < 100)
+ else if (jdbcUrl != null && driverClassName == null)
{
- logger.warn("connectionTimeout is less than 100ms, did you specify the wrong time unit? Using default instead.");
- connectionTimeout = CONNECTION_TIMEOUT;
+ logger.error("when specifying jdbcUrl, driverClassName must also be specified");
+ throw new IllegalStateException("when specifying jdbcUrl, driverClassName must also be specified");
}
-
- if (dataSource == null && dataSourceClassName == null)
+ else if (driverClassName != null && jdbcUrl != null)
{
- logger.error("one of either dataSource or dataSourceClassName must be specified");
- throw new IllegalStateException("one of either dataSource or dataSourceClassName must be specified");
+ // OK
+ }
+ else if (dataSource == null && dataSourceClassName == null)
+ {
+ logger.error("one of either dataSource, dataSourceClassName, or jdbcUrl and driverClassName must be specified");
+ throw new IllegalArgumentException("one of either dataSource or dataSourceClassName must be specified");
}
else if (dataSource != null && dataSourceClassName != null)
{
logger.warn("both dataSource and dataSourceClassName are specified, ignoring dataSourceClassName");
}
- if (idleTimeout < 0)
+ if (connectionTestQuery != null)
{
- logger.error("idleTimeout cannot be negative.");
- throw new IllegalStateException("idleTimeout cannot be negative.");
+ isJdbc4connectionTest = false;
}
- else if (idleTimeout < 30000 && idleTimeout != 0)
+ else if (!isJdbc4connectionTest)
{
- logger.warn("idleTimeout is less than 30000ms, did you specify the wrong time unit? Using default instead.");
- idleTimeout = IDLE_TIMEOUT;
+ logger.error("Either jdbc4ConnectionTest must be enabled or a connectionTestQuery must be specified");
+ throw new IllegalStateException("Either jdbc4ConnectionTest must be enabled or a connectionTestQuery must be specified");
}
- if (!isJdbc4connectionTest && connectionTestQuery == null)
+ if (transactionIsolationName != null)
{
- logger.error("Either jdbc4ConnectionTest must be enabled or a connectionTestQuery must be specified.");
- throw new IllegalStateException("Either jdbc4ConnectionTest must be enabled or a connectionTestQuery must be specified.");
+ try
+ {
+ Field field = Connection.class.getField(transactionIsolationName);
+ int level = field.getInt(null);
+ this.transactionIsolation = level;
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Invalid transaction isolation value: " + transactionIsolationName);
+ }
}
+ }
- if (leakDetectionThreshold != 0 && leakDetectionThreshold < 10000)
+ private void validateNumerics()
+ {
+ Logger logger = LoggerFactory.getLogger(getClass());
+
+ if (connectionTimeout == Integer.MAX_VALUE)
{
- logger.warn("leakDetectionThreshold is less than 10000ms, did you specify the wrong time unit? Disabling leak detection.");
- leakDetectionThreshold = 0;
+ logger.warn("No connection wait timeout is set, this might cause an infinite wait");
+ }
+ else if (connectionTimeout < TimeUnit.MILLISECONDS.toMillis(250))
+ {
+ logger.warn("connectionTimeout is less than 250ms, did you specify the wrong time unit? Using default instead");
+ connectionTimeout = CONNECTION_TIMEOUT;
}
- if (maxPoolSize < minPoolSize)
+ if (minIdle < 0)
{
- logger.warn("maxPoolSize is less than minPoolSize, forcing them equal.");
- maxPoolSize = minPoolSize;
+ minIdle = maxPoolSize;
+ }
+
+ if (idleTimeout < 0)
+ {
+ logger.error("idleTimeout cannot be negative.");
+ throw new IllegalArgumentException("idleTimeout cannot be negative");
+ }
+ else if (idleTimeout < TimeUnit.SECONDS.toMillis(30) && idleTimeout != 0)
+ {
+ logger.warn("idleTimeout is less than 30000ms, did you specify the wrong time unit? Using default instead");
+ idleTimeout = IDLE_TIMEOUT;
+ }
+
+ if (leakDetectionThreshold != 0 && leakDetectionThreshold < TimeUnit.SECONDS.toMillis(10))
+ {
+ logger.warn("leakDetectionThreshold is less than 10000ms, did you specify the wrong time unit? Disabling leak detection");
+ leakDetectionThreshold = 0;
}
if (maxLifetime < 0)
{
logger.error("maxLifetime cannot be negative.");
- throw new IllegalStateException("maxLifetime cannot be negative.");
+ throw new IllegalArgumentException("maxLifetime cannot be negative.");
}
- else if (maxLifetime < 120000 && maxLifetime != 0)
+ else if (maxLifetime < TimeUnit.SECONDS.toMillis(120) && maxLifetime != 0)
{
logger.warn("maxLifetime is less than 120000ms, did you specify the wrong time unit? Using default instead.");
maxLifetime = MAX_LIFETIME;
}
-
- if (transactionIsolationName != null)
- {
- try
- {
- Field field = Connection.class.getField(transactionIsolationName);
- int level = field.getInt(null);
- this.transactionIsolation = level;
- }
- catch (Exception e)
- {
- throw new IllegalArgumentException("Invalid transaction isolation value: " + transactionIsolationName);
- }
- }
}
IConnectionCustomizer getConnectionCustomizer()
diff --git a/src/main/java/com/zaxxer/hikari/HikariConfigMBean.java b/src/main/java/com/zaxxer/hikari/HikariConfigMBean.java
index 543dcd46..d9384fd8 100644
--- a/src/main/java/com/zaxxer/hikari/HikariConfigMBean.java
+++ b/src/main/java/com/zaxxer/hikari/HikariConfigMBean.java
@@ -23,32 +23,6 @@ package com.zaxxer.hikari;
*/
public interface HikariConfigMBean
{
- /**
- * This is a per-connection attempt retry count used during new connection creation (acquisition).
- * If a connection creation attempt fails there will be a wait of {@link #getAcquireRetryDelay} milliseconds
- * followed by another attempt, up to the number of retries configured by this property.
- *
- * @return the acquire retry count
- */
- int getAcquireRetries();
-
- /**
- * This is a per-connection attempt retry count used during new connection creation (acquisition).
- * If a connection creation attempt fails there will be a wait of {@link #setAcquireRetryDelay} milliseconds
- * followed by another attempt, up to the number of retries configured by this property.
- *
- * @param acquireRetries the acquire retry count
- */
- void setAcquireRetries(int acquireRetries);
-
- /**
- * This property controls the number of milliseconds to delay between attempts to acquire a connection
- * to the database. If acquireRetries is 0, this property has no effect.
- *
- * @param acquireRetryDelayMs the acquire retry delay in milliseconds
- */
- void setAcquireRetryDelay(long acquireRetryDelayMs);
-
/**
* This is for "legacy" databases that do not support the JDBC4 {@code Connection.isValid()} API. This is the
* query that will be executed just before a connection is given to you from the pool to validate that
@@ -135,7 +109,7 @@ public interface HikariConfigMBean
*
* @return the minimum number of connections in the pool
*/
- int getMinimumPoolSize();
+ int getMinimumIdle();
/**
* The property controls the minimum number of connections that HikariCP tries to maintain in the pool,
@@ -144,7 +118,7 @@ public interface HikariConfigMBean
*
* @param minPoolSize the minimum number of connections in the pool
*/
- void setMinimumPoolSize(int minPoolSize);
+ void setMinimumIdle(int minIdle);
/**
* The property controls the minimum number of connections that HikariCP tries to maintain in the pool,
diff --git a/src/main/java/com/zaxxer/hikari/HikariDataSource.java b/src/main/java/com/zaxxer/hikari/HikariDataSource.java
index 2ac26288..747365df 100644
--- a/src/main/java/com/zaxxer/hikari/HikariDataSource.java
+++ b/src/main/java/com/zaxxer/hikari/HikariDataSource.java
@@ -20,11 +20,12 @@ import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
+import java.util.HashMap;
import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.zaxxer.hikari.proxy.IHikariConnectionProxy;
+import com.zaxxer.hikari.util.DriverDataSource;
/**
* The HikariCP pooled DataSource.
@@ -33,12 +34,12 @@ import org.slf4j.LoggerFactory;
*/
public class HikariDataSource extends HikariConfig implements DataSource
{
- private static final Logger LOGGER = LoggerFactory.getLogger(HikariDataSource.class);
-
+ private final HashMap multiPool;
private volatile boolean isShutdown;
private int loginTimeout;
- HikariPool fastPathPool;
+ /* Package scopped for testing */
+ final HikariPool fastPathPool;
volatile HikariPool pool;
/**
@@ -50,6 +51,8 @@ public class HikariDataSource extends HikariConfig implements DataSource
public HikariDataSource()
{
super();
+ fastPathPool = null;
+ multiPool = new HashMap();
}
/**
@@ -59,24 +62,28 @@ public class HikariDataSource extends HikariConfig implements DataSource
*/
public HikariDataSource(HikariConfig configuration)
{
- super();
+ configuration.validate();
configuration.copyState(this);
+ multiPool = new HashMap();
pool = fastPathPool = new HikariPool(this);
+ multiPool.put(new MultiPoolKey(getUsername(), getPassword()), pool);
}
/** {@inheritDoc} */
+ @Override
public Connection getConnection() throws SQLException
{
if (isShutdown)
{
- throw new IllegalStateException("The datasource has been shutdown.");
+ throw new SQLException("Pool has been shutdown");
}
-
+
if (fastPathPool != null)
{
return fastPathPool.getConnection();
}
+ // See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
HikariPool result = pool;
if (result == null)
{
@@ -85,7 +92,9 @@ public class HikariDataSource extends HikariConfig implements DataSource
result = pool;
if (result == null)
{
+ validate();
pool = result = new HikariPool(this);
+ multiPool.put(new MultiPoolKey(getUsername(), getPassword()), pool);
}
}
}
@@ -94,20 +103,39 @@ public class HikariDataSource extends HikariConfig implements DataSource
}
/** {@inheritDoc} */
+ @Override
public Connection getConnection(String username, String password) throws SQLException
{
- LOGGER.warn("getConnection() with username and password is not supported, calling getConnection() instead");
+ if (isShutdown)
+ {
+ throw new SQLException("Pool has been shutdown");
+ }
+
+ final MultiPoolKey key = new MultiPoolKey(username, password);
+
+ HikariPool hikariPool;
+ synchronized (multiPool)
+ {
+ hikariPool = multiPool.get(key);
+ if (hikariPool == null)
+ {
+ hikariPool = new HikariPool(this, username, password);
+ multiPool.put(key, hikariPool);
+ }
+ }
- return getConnection();
+ return hikariPool.getConnection();
}
/** {@inheritDoc} */
+ @Override
public PrintWriter getLogWriter() throws SQLException
{
return (pool.dataSource != null ? pool.dataSource.getLogWriter() : null);
}
/** {@inheritDoc} */
+ @Override
public void setLogWriter(PrintWriter out) throws SQLException
{
if (pool.dataSource != null)
@@ -117,12 +145,14 @@ public class HikariDataSource extends HikariConfig implements DataSource
}
/** {@inheritDoc} */
+ @Override
public void setLoginTimeout(int seconds) throws SQLException
{
this.loginTimeout = seconds;
}
/** {@inheritDoc} */
+ @Override
public int getLoginTimeout() throws SQLException
{
return loginTimeout;
@@ -135,16 +165,38 @@ public class HikariDataSource extends HikariConfig implements DataSource
}
/** {@inheritDoc} */
+ @Override
+ @SuppressWarnings("unchecked")
public T unwrap(Class iface) throws SQLException
{
- // TODO Auto-generated method stub
- return null;
+ if (pool != null && iface.isInstance(pool.dataSource))
+ {
+ return (T) pool.dataSource;
+ }
+
+ throw new SQLException("Wrapped connection is not an instance of " + iface);
}
/** {@inheritDoc} */
+ @Override
public boolean isWrapperFor(Class> iface) throws SQLException
{
- return (this.getClass().isAssignableFrom(iface));
+ return (pool != null & pool.dataSource.getClass().isAssignableFrom(iface));
+ }
+
+ /**
+ * Evict a connection from the pool. Use caution using this method, if you
+ * evict the same connection more than one time, the internal pool accounting
+ * will become invalid and the pool may stop functioning.
+ *
+ * @param connection the connection to evict from the pool
+ */
+ public void evictConnection(Connection connection)
+ {
+ if (!isShutdown && pool != null && connection instanceof IHikariConnectionProxy)
+ {
+ pool.closeConnection((IHikariConnectionProxy) connection);
+ }
}
/**
@@ -160,12 +212,32 @@ public class HikariDataSource extends HikariConfig implements DataSource
*/
public void shutdown()
{
- boolean shutdown = isShutdown;
+ if (isShutdown)
+ {
+ return;
+ }
+
isShutdown = true;
- if (!shutdown)
+
+ if (pool != null)
{
pool.shutdown();
- pool = null;
+ if (pool.dataSource instanceof DriverDataSource)
+ {
+ ((DriverDataSource) pool.dataSource).shutdown();
+ }
+ }
+
+ if (!multiPool.isEmpty())
+ {
+ for (HikariPool hikariPool : multiPool.values())
+ {
+ hikariPool.shutdown();
+ if (hikariPool.dataSource instanceof DriverDataSource)
+ {
+ ((DriverDataSource) hikariPool.dataSource).shutdown();
+ }
+ }
}
}
@@ -175,4 +247,46 @@ public class HikariDataSource extends HikariConfig implements DataSource
{
return String.format("HikariDataSource (%s)", pool);
}
+
+ private static class MultiPoolKey
+ {
+ private String username;
+ private String password;
+
+ MultiPoolKey(String username, String password)
+ {
+ this.username = username;
+ this.password = password;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return (password == null ? 0 : password.hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ MultiPoolKey otherKey = ((MultiPoolKey) obj);
+ if (username != null && !username.equals(otherKey.username))
+ {
+ return false;
+ }
+ else if (username != otherKey.username)
+ {
+ return false;
+ }
+ else if (password != null && !password.equals(otherKey.password))
+ {
+ return false;
+ }
+ else if (password != otherKey.password)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
}
diff --git a/src/main/java/com/zaxxer/hikari/HikariPool.java b/src/main/java/com/zaxxer/hikari/HikariPool.java
index 100e24b6..b0ebab40 100644
--- a/src/main/java/com/zaxxer/hikari/HikariPool.java
+++ b/src/main/java/com/zaxxer/hikari/HikariPool.java
@@ -22,6 +22,7 @@ import java.sql.Statement;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -30,10 +31,15 @@ import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.zaxxer.hikari.metrics.CodaHaleMetricsTracker;
+import com.zaxxer.hikari.metrics.MetricsTracker;
+import com.zaxxer.hikari.metrics.MetricsTracker.Context;
import com.zaxxer.hikari.proxy.IHikariConnectionProxy;
import com.zaxxer.hikari.proxy.ProxyFactory;
import com.zaxxer.hikari.util.ConcurrentBag;
import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener;
+import com.zaxxer.hikari.util.DriverDataSource;
+import com.zaxxer.hikari.util.PoolUtilities;
import com.zaxxer.hikari.util.PropertyBeanSetter;
/**
@@ -50,61 +56,60 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
private final IConnectionCustomizer connectionCustomizer;
private final HikariConfig configuration;
- private final ConcurrentBag idleConnectionBag;
+ private final ConcurrentBag connectionBag;
+ private final ThreadPoolExecutor addConnectionExecutor;
+ private final MetricsTracker metricsTracker;
- private final Timer houseKeepingTimer;
-
- private final long leakDetectionThreshold;
- private final AtomicInteger totalConnections;
private final boolean isAutoCommit;
- private final boolean jdbc4ConnectionTest;
+ private final boolean isIsolateInternalQueries;
+ private final boolean isReadOnly;
private final boolean isRegisteredMbeans;
+ private final boolean isJdbc4ConnectionTest;
+ private final long leakDetectionThreshold;
+ private final AtomicInteger totalConnections;
+ private final Timer houseKeepingTimer;
private final String catalog;
+ private final String username;
+ private final String password;
+
+ private volatile boolean isShutdown;
+ private volatile long lastConnectionFailureTime;
private int transactionIsolation;
- private volatile boolean shutdown;
- private boolean debug;
+ private boolean isDebug;
+
+ HikariPool(HikariConfig configuration)
+ {
+ this(configuration, configuration.getUsername(), configuration.getPassword());
+ }
/**
* Construct a HikariPool with the specified configuration.
*
* @param configuration a HikariConfig instance
*/
- HikariPool(HikariConfig configuration)
+ HikariPool(HikariConfig configuration, String username, String password)
{
- configuration.validate();
-
this.configuration = configuration;
+ this.username = username;
+ this.password = password;
+
this.totalConnections = new AtomicInteger();
- this.idleConnectionBag = new ConcurrentBag();
- this.idleConnectionBag.addBagStateListener(this);
- this.debug = LOGGER.isDebugEnabled();
+ this.connectionBag = new ConcurrentBag();
+ this.connectionBag.addBagStateListener(this);
+ this.isDebug = LOGGER.isDebugEnabled();
this.catalog = configuration.getCatalog();
this.connectionCustomizer = configuration.getConnectionCustomizer();
this.isAutoCommit = configuration.isAutoCommit();
+ this.isIsolateInternalQueries = configuration.isIsolateInternalQueries();
+ this.isReadOnly = configuration.isReadOnly();
this.isRegisteredMbeans = configuration.isRegisterMbeans();
- this.jdbc4ConnectionTest = configuration.isJdbc4ConnectionTest();
+ this.isJdbc4ConnectionTest = configuration.isJdbc4ConnectionTest();
this.leakDetectionThreshold = configuration.getLeakDetectionThreshold();
this.transactionIsolation = configuration.getTransactionIsolation();
+ this.metricsTracker = (configuration.isRecordMetrics() ? new CodaHaleMetricsTracker(configuration.getPoolName()) : new MetricsTracker());
- if (configuration.getDataSource() == null)
- {
- String dsClassName = configuration.getDataSourceClassName();
- try
- {
- Class> clazz = this.getClass().getClassLoader().loadClass(dsClassName);
- this.dataSource = (DataSource) clazz.newInstance();
- PropertyBeanSetter.setTargetFromProperties(dataSource, configuration.getDataSourceProperties());
- }
- catch (Exception e)
- {
- throw new RuntimeException("Could not create datasource instance: " + dsClassName, e);
- }
- }
- else
- {
- this.dataSource = configuration.getDataSource();
- }
+ this.dataSource = initializeDataSource();
if (isRegisteredMbeans)
{
@@ -113,10 +118,11 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
houseKeepingTimer = new Timer("Hikari Housekeeping Timer", true);
- fillPool();
+ addConnectionExecutor = PoolUtilities.createThreadPoolExecutor(configuration.getMaximumPoolSize(), "HikariCP connection filler");
- long idleTimeout = configuration.getIdleTimeout();
- if (idleTimeout > 0 || configuration.getMaxLifetime() > 0)
+ fillPool();
+
+ if (configuration.getIdleTimeout() > 0 || configuration.getMaxLifetime() > 0)
{
long delayPeriod = Long.getLong("com.zaxxer.hikari.housekeeping.period", TimeUnit.SECONDS.toMillis(30));
houseKeepingTimer.scheduleAtFixedRate(new HouseKeeper(), delayPeriod, delayPeriod);
@@ -131,21 +137,16 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
*/
Connection getConnection() throws SQLException
{
- if (shutdown)
- {
- throw new SQLException("Pool has been shutdown");
- }
-
+ final long start = System.currentTimeMillis();
+ final Context context = metricsTracker.recordConnectionRequest(start);
+ long timeout = configuration.getConnectionTimeout();
try
{
- long timeout = configuration.getConnectionTimeout();
- final long start = System.currentTimeMillis();
do
{
- IHikariConnectionProxy connectionProxy = idleConnectionBag.borrow(timeout, TimeUnit.MILLISECONDS);
- if (connectionProxy == null)
+ IHikariConnectionProxy connectionProxy = connectionBag.borrow(timeout, TimeUnit.MILLISECONDS);
+ if (connectionProxy == null) // We timed out... break and throw exception
{
- // We timed out... break and throw exception
break;
}
@@ -153,34 +154,30 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
if (System.currentTimeMillis() - connectionProxy.getLastAccess() > 1000 && !isConnectionAlive(connectionProxy, timeout))
{
- // Throw away the dead connection, try again
- closeConnection(connectionProxy);
+ closeConnection(connectionProxy); // Throw away the dead connection, try again
timeout -= (System.currentTimeMillis() - start);
continue;
}
-
- if (leakDetectionThreshold > 0)
+ else if (leakDetectionThreshold > 0)
{
connectionProxy.captureStack(leakDetectionThreshold, houseKeepingTimer);
}
return connectionProxy;
-
}
while (timeout > 0);
- logPoolState();
-
- String msg = String.format("Timeout of %dms encountered waiting for connection.", configuration.getConnectionTimeout());
- LOGGER.error(msg);
logPoolState("Timeout failure ");
-
- throw new SQLException(msg);
+ throw new SQLException(String.format("Timeout of %dms encountered waiting for connection.", configuration.getConnectionTimeout()));
}
catch (InterruptedException e)
{
return null;
}
+ finally
+ {
+ context.stop();
+ }
}
/**
@@ -191,9 +188,11 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
*/
public void releaseConnection(IHikariConnectionProxy connectionProxy)
{
- if (!connectionProxy.isBrokenConnection() && !shutdown)
+ metricsTracker.recordConnectionUsage(System.currentTimeMillis() - connectionProxy.getLastOpenTime());
+
+ if (!connectionProxy.isBrokenConnection() && !isShutdown)
{
- idleConnectionBag.requite(connectionProxy);
+ connectionBag.requite(connectionProxy);
}
else
{
@@ -210,11 +209,12 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
void shutdown()
{
- LOGGER.info("HikariCP pool " + configuration.getPoolName() + " is being shutdown.");
- logPoolState("State at shutdown ");
-
- shutdown = true;
+ isShutdown = true;
houseKeepingTimer.cancel();
+ addConnectionExecutor.shutdown();
+
+ LOGGER.info("HikariCP pool {} is being shutdown.", configuration.getPoolName());
+ logPoolState("State at shutdown ");
closeIdleConnections();
@@ -228,10 +228,37 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
// IBagStateListener methods
// ***********************************************************************
+ /** {@inheritDoc} */
@Override
- public void bagIsEmpty()
+ public void addBagItem()
{
- addConnections(AddConnectionStrategy.ONLY_IF_EMPTY);
+ class AddConnection implements Runnable {
+ public void run()
+ {
+ int sleepBackoff = 200;
+ while (totalConnections.get() < configuration.getMaximumPoolSize())
+ {
+ final int minIdle = configuration.getMinimumIdle();
+ if (minIdle != 0 && getIdleConnections() >= minIdle)
+ {
+ break;
+ }
+ else if (!addConnection())
+ {
+ PoolUtilities.quietlySleep(sleepBackoff);
+ sleepBackoff = (int) Math.min(1000f, ((float) sleepBackoff) * 1.5);
+ continue;
+ }
+
+ if (minIdle == 0) // This break is here so we only add one connection when demanded
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ addConnectionExecutor.submit(new AddConnection());
}
// ***********************************************************************
@@ -239,41 +266,44 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
// ***********************************************************************
/** {@inheritDoc} */
+ @Override
public int getActiveConnections()
{
return Math.min(configuration.getMaximumPoolSize(), totalConnections.get() - getIdleConnections());
}
/** {@inheritDoc} */
+ @Override
public int getIdleConnections()
{
- return idleConnectionBag.values(ConcurrentBag.STATE_NOT_IN_USE).size();
+ return connectionBag.getCount(ConcurrentBag.STATE_NOT_IN_USE);
}
/** {@inheritDoc} */
+ @Override
public int getTotalConnections()
{
return totalConnections.get();
}
/** {@inheritDoc} */
+ @Override
public int getThreadsAwaitingConnection()
{
- return idleConnectionBag.getPendingQueue();
+ return connectionBag.getPendingQueue();
}
/** {@inheritDoc} */
+ @Override
public void closeIdleConnections()
{
- List list = idleConnectionBag.values(ConcurrentBag.STATE_NOT_IN_USE);
+ List list = connectionBag.values(ConcurrentBag.STATE_NOT_IN_USE);
for (IHikariConnectionProxy connectionProxy : list)
{
- if (!idleConnectionBag.reserve(connectionProxy))
+ if (connectionBag.reserve(connectionProxy))
{
- continue;
+ closeConnection(connectionProxy);
}
-
- closeConnection(connectionProxy);
}
}
@@ -282,133 +312,53 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
// ***********************************************************************
/**
- * Fill the pool up to the minimum size.
+ * Create and add a single connection to the pool.
*/
- private void fillPool()
+ private boolean addConnection()
{
- // maxIters avoids an infinite loop filling the pool if no connections can be acquired
- int maxIters = configuration.getMinimumPoolSize() * configuration.getAcquireRetries();
- while (maxIters-- > 0 && totalConnections.get() < configuration.getMinimumPoolSize())
+ Connection connection = null;
+ try
{
- int beforeCount = totalConnections.get();
- addConnection();
- if (configuration.isInitializationFailFast() && beforeCount == totalConnections.get())
+ // Speculative increment of totalConnections with expectation of success (first time through)
+ if (totalConnections.incrementAndGet() > configuration.getMaximumPoolSize())
{
- throw new RuntimeException("Fail-fast during pool initialization");
+ totalConnections.decrementAndGet();
+ return true;
}
- }
- logPoolState("Initial fill ");
- }
+ connection = (username == null && password == null) ? dataSource.getConnection() : dataSource.getConnection(username, password);
- /**
- * Add connections to the pool, not exceeding the maximum allowed.
- */
- private void addConnections(AddConnectionStrategy strategy)
- {
- switch (strategy)
- {
- case ONLY_IF_EMPTY:
- addConnection();
- break;
- case MAINTAIN_MINIMUM:
- final int min = configuration.getMinimumPoolSize();
- for (int maxIterations = 0; maxIterations < min && totalConnections.get() < min; maxIterations++)
+ transactionIsolation = (transactionIsolation < 0 ? connection.getTransactionIsolation() : transactionIsolation);
+
+ if (connectionCustomizer != null)
{
- addConnection();
+ connectionCustomizer.customize(connection);
}
- break;
- }
- }
- /**
- * Create and add a single connection to the pool.
- */
- private void addConnection()
- {
- final int acquisitionTimeout = (int) configuration.getConnectionTimeout();
- int retries = configuration.getAcquireRetries();
- int loginTimeout = 2000;
- if (retries == 0)
- {
- loginTimeout = (acquisitionTimeout == 0 ? Integer.MAX_VALUE : acquisitionTimeout);
+ PoolUtilities.executeSqlAutoCommit(connection, configuration.getConnectionInitSql());
+
+ IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, connection, transactionIsolation, isAutoCommit, isReadOnly, catalog);
+ proxyConnection.resetConnectionState();
+ connectionBag.add(proxyConnection);
+ return true;
}
- else if (acquisitionTimeout > 0)
+ catch (Exception e)
{
- loginTimeout = (acquisitionTimeout / (retries + 1));
- }
+ // We failed, so undo speculative increment of totalConnections
+ totalConnections.decrementAndGet();
- while (!shutdown)
- {
- try
+ if (connection != null)
{
- // Speculative increment of totalConnections with expectation of success
- if (totalConnections.incrementAndGet() > configuration.getMaximumPoolSize())
- {
- totalConnections.decrementAndGet();
- break;
- }
-
- dataSource.setLoginTimeout(loginTimeout);
- Connection connection = dataSource.getConnection();
-
- if (transactionIsolation < 0)
- {
- transactionIsolation = connection.getTransactionIsolation();
- }
-
- if (connectionCustomizer != null)
- {
- connectionCustomizer.customize(connection);
- }
-
- IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, connection, transactionIsolation, isAutoCommit, catalog);
-
- String initSql = configuration.getConnectionInitSql();
- if (initSql != null && initSql.length() > 0)
- {
- connection.setAutoCommit(true);
- Statement statement = connection.createStatement();
- try
- {
- statement.execute(initSql);
- }
- finally
- {
- statement.close();
- }
- }
-
- proxyConnection.resetConnectionState();
- idleConnectionBag.add(proxyConnection);
- break;
+ PoolUtilities.quietlyCloseConnection(connection);
}
- catch (Exception e)
- {
- if (retries++ > configuration.getAcquireRetries())
- {
- if (debug)
- {
- LOGGER.error("Maximum connection creation retries exceeded: {}", e.getMessage(), e);
- }
- else
- {
- LOGGER.error("Maximum connection creation retries exceeded: {}", e.getMessage());
- }
- totalConnections.decrementAndGet();
- break;
- }
- try
- {
- Thread.sleep(configuration.getAcquireRetryDelay());
- }
- catch (InterruptedException e1)
- {
- totalConnections.decrementAndGet();
- break;
- }
+ long now = System.currentTimeMillis();
+ if (now - lastConnectionFailureTime > 1000 || isDebug)
+ {
+ LOGGER.warn("Connection attempt to database failed (not every attempt is logged): {}", e.getMessage(), (isDebug ? e : null));
}
+ lastConnectionFailureTime = now;
+ return false;
}
}
@@ -423,18 +373,14 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
{
try
{
- try
- {
- if (timeoutMs < 1000)
- {
- timeoutMs = 1000;
- }
-
- if (jdbc4ConnectionTest)
- {
- return connection.isValid((int) TimeUnit.MILLISECONDS.toSeconds(timeoutMs));
- }
+ timeoutMs = Math.max(1000, timeoutMs);
+ if (isJdbc4ConnectionTest)
+ {
+ connection.isValid((int) TimeUnit.MILLISECONDS.toSeconds(timeoutMs));
+ }
+ else
+ {
Statement statement = connection.createStatement();
try
{
@@ -446,12 +392,10 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
statement.close();
}
}
- finally
+
+ if (isIsolateInternalQueries && !isAutoCommit)
{
- if (!isAutoCommit)
- {
- connection.commit();
- }
+ connection.rollback();
}
return true;
@@ -463,12 +407,33 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
}
}
+ /**
+ * Fill the pool up to the minimum size.
+ */
+ private void fillPool()
+ {
+ if (configuration.isInitializationFailFast())
+ {
+ for (int maxIters = configuration.getMinimumIdle(); maxIters > 0; maxIters--)
+ {
+ if (!addConnection())
+ {
+ throw new RuntimeException("Fail-fast during pool initialization");
+ }
+ }
+ }
+ else if (configuration.getMinimumIdle() > 0)
+ {
+ addBagItem();
+ }
+ }
+
/**
* Permanently close a connection.
*
* @param connectionProxy the connection to actually close
*/
- private void closeConnection(IHikariConnectionProxy connectionProxy)
+ void closeConnection(IHikariConnectionProxy connectionProxy)
{
try
{
@@ -481,8 +446,33 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
}
finally
{
- idleConnectionBag.remove(connectionProxy);
+ connectionBag.remove(connectionProxy);
+ }
+ }
+
+ private DataSource initializeDataSource()
+ {
+ String dsClassName = configuration.getDataSourceClassName();
+ if (configuration.getDataSource() == null && dsClassName != null)
+ {
+ try
+ {
+ Class> clazz = this.getClass().getClassLoader().loadClass(dsClassName);
+ DataSource dataSource = (DataSource) clazz.newInstance();
+ PropertyBeanSetter.setTargetFromProperties(dataSource, configuration.getDataSourceProperties());
+ return dataSource;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Could not create datasource instance: " + dsClassName, e);
+ }
+ }
+ else if (configuration.getJdbcUrl() != null)
+ {
+ return new DriverDataSource(configuration.getJdbcUrl(), configuration.getDataSourceProperties(), username, password);
}
+
+ return configuration.getDataSource();
}
private void logPoolState(String... prefix)
@@ -498,9 +488,10 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
*/
private class HouseKeeper extends TimerTask
{
+ @Override
public void run()
{
- debug = LOGGER.isDebugEnabled();
+ isDebug = LOGGER.isDebugEnabled();
houseKeepingTimer.purge();
logPoolState("Before pool cleanup ");
@@ -509,33 +500,28 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
final long idleTimeout = configuration.getIdleTimeout();
final long maxLifetime = configuration.getMaxLifetime();
- for (IHikariConnectionProxy connectionProxy : idleConnectionBag.values(ConcurrentBag.STATE_NOT_IN_USE))
+ for (IHikariConnectionProxy connectionProxy : connectionBag.values(ConcurrentBag.STATE_NOT_IN_USE))
{
- if (!idleConnectionBag.reserve(connectionProxy))
- {
- continue;
- }
-
- if ((idleTimeout > 0 && now > connectionProxy.getLastAccess() + idleTimeout)
- || (maxLifetime > 0 && now > connectionProxy.getCreationTime() + maxLifetime))
+ if (connectionBag.reserve(connectionProxy))
{
- closeConnection(connectionProxy);
- }
- else
- {
- idleConnectionBag.unreserve(connectionProxy);
+ if ((idleTimeout > 0 && now > connectionProxy.getLastAccess() + idleTimeout)
+ ||
+ (maxLifetime > 0 && now > connectionProxy.getCreationTime() + maxLifetime))
+ {
+ closeConnection(connectionProxy);
+ continue;
+ }
+
+ connectionBag.unreserve(connectionProxy);
}
}
-
- addConnections(AddConnectionStrategy.MAINTAIN_MINIMUM);
-
+
logPoolState("After pool cleanup ");
- }
- }
- private static enum AddConnectionStrategy
- {
- ONLY_IF_EMPTY,
- MAINTAIN_MINIMUM
+ if (getIdleConnections() < configuration.getMinimumIdle() && totalConnections.get() < configuration.getMaximumPoolSize())
+ {
+ addBagItem(); // TRY to maintain minimum connections
+ }
+ }
}
}
diff --git a/src/main/java/com/zaxxer/hikari/hibernate/HikariConfigurationUtil.java b/src/main/java/com/zaxxer/hikari/hibernate/HikariConfigurationUtil.java
index bbaf1b2a..07690c1b 100644
--- a/src/main/java/com/zaxxer/hikari/hibernate/HikariConfigurationUtil.java
+++ b/src/main/java/com/zaxxer/hikari/hibernate/HikariConfigurationUtil.java
@@ -42,20 +42,24 @@ public class HikariConfigurationUtil
@SuppressWarnings("rawtypes")
public static HikariConfig loadConfiguration(Map props)
{
- Properties hicaryProps = new Properties();
- copyProperty(AvailableSettings.ISOLATION, props, "transactionIsolation", hicaryProps);
- copyProperty(AvailableSettings.AUTOCOMMIT, props, "autoCommit", hicaryProps);
+ Properties hikariProps = new Properties();
+ copyProperty(AvailableSettings.ISOLATION, props, "transactionIsolation", hikariProps);
+ copyProperty(AvailableSettings.AUTOCOMMIT, props, "autoCommit", hikariProps);
+ copyProperty(AvailableSettings.DRIVER, props, "driverClassName", hikariProps);
+ copyProperty(AvailableSettings.URL, props, "jdbcUrl", hikariProps);
+ copyProperty(AvailableSettings.USER, props, "username", hikariProps);
+ copyProperty(AvailableSettings.PASS, props, "password", hikariProps);
for (Object keyo : props.keySet())
{
String key = (String) keyo;
if (key.startsWith(CONFIG_PREFIX))
{
- hicaryProps.setProperty(key.substring(CONFIG_PREFIX.length()), (String) props.get(key));
+ hikariProps.setProperty(key.substring(CONFIG_PREFIX.length()), (String) props.get(key));
}
}
- return new HikariConfig(hicaryProps);
+ return new HikariConfig(hikariProps);
}
@SuppressWarnings("rawtypes")
diff --git a/src/main/java/com/zaxxer/hikari/metrics/CodaHaleMetricsTracker.java b/src/main/java/com/zaxxer/hikari/metrics/CodaHaleMetricsTracker.java
new file mode 100644
index 00000000..3bf21404
--- /dev/null
+++ b/src/main/java/com/zaxxer/hikari/metrics/CodaHaleMetricsTracker.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013,2014 Brett Wooldridge
+ *
+ * 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.zaxxer.hikari.metrics;
+
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.Timer;
+import com.zaxxer.hikari.HikariPool;
+
+public final class CodaHaleMetricsTracker extends MetricsTracker
+{
+ private MetricRegistry registry;
+ private Timer connectionObtainTimer;
+ private Histogram connectionUsage;
+
+ public CodaHaleMetricsTracker(String poolName)
+ {
+ registry = new MetricRegistry();
+ connectionObtainTimer = registry.timer(MetricRegistry.name(HikariPool.class, "connection", "wait"));
+ connectionUsage = registry.histogram(MetricRegistry.name(HikariPool.class, "connection", "usage"));
+ }
+
+ @Override
+ public Context recordConnectionRequest(long requestTime)
+ {
+ return new Context(connectionObtainTimer);
+ }
+
+ @Override
+ public void recordConnectionUsage(long usageMilleseconds)
+ {
+ connectionUsage.update(usageMilleseconds);
+ }
+
+ public static final class Context extends MetricsTracker.Context
+ {
+ Timer.Context innerContext;
+
+ Context(Timer timer)
+ {
+ innerContext = timer.time();
+ }
+
+ public void stop()
+ {
+ if (innerContext != null)
+ {
+ innerContext.stop();
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/zaxxer/hikari/metrics/MetricsTracker.java b/src/main/java/com/zaxxer/hikari/metrics/MetricsTracker.java
new file mode 100644
index 00000000..1dfb5ead
--- /dev/null
+++ b/src/main/java/com/zaxxer/hikari/metrics/MetricsTracker.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013,2014 Brett Wooldridge
+ *
+ * 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.zaxxer.hikari.metrics;
+
+
+/**
+ * This class does absolutely nothing.
+ *
+ * @author Brett Wooldridge
+ */
+public class MetricsTracker
+{
+ private static final Context NO_CONTEXT = new Context();
+
+ public static class Context
+ {
+ public void stop()
+ {
+ }
+ }
+
+ public Context recordConnectionRequest(long start)
+ {
+ return NO_CONTEXT;
+ }
+
+ public void recordConnectionUsage(long usageMilleseconds)
+ {
+ }
+}
diff --git a/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java b/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java
index 5d7255b3..75647341 100644
--- a/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java
+++ b/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013,2014 Brett Wooldridge
+ * Copyright (C) 2013, 2014 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,22 +51,24 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
private final HikariPool parentPool;
private final int defaultIsolationLevel;
private final boolean defaultAutoCommit;
+ private final boolean defaultReadOnly;
private final String defaultCatalog;
private final AtomicInteger state;
- private boolean isClosed;
private boolean forceClose;
- private boolean isTransactionIsolationDirty;
private boolean isAutoCommitDirty;
private boolean isCatalogDirty;
+ private boolean isClosed;
+ private boolean isReadOnlyDirty;
+ private boolean isTransactionIsolationDirty;
private volatile long lastAccess;
+ private long uncloseTime;
private StackTraceElement[] leakTrace;
private TimerTask leakTask;
private final int hashCode;
-
// static initializer
static
{
@@ -79,12 +81,13 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
SQL_ERRORS.add("JZ0C1"); // Sybase disconnect error
}
- protected ConnectionProxy(HikariPool pool, Connection connection, int defaultIsolationLevel, boolean defaultAutoCommit, String defaultCatalog)
+ protected ConnectionProxy(HikariPool pool, Connection connection, int defaultIsolationLevel, boolean defaultAutoCommit, boolean defaultReadOnly, String defaultCatalog)
{
this.parentPool = pool;
this.delegate = connection;
this.defaultIsolationLevel = defaultIsolationLevel;
this.defaultAutoCommit = defaultAutoCommit;
+ this.defaultReadOnly = defaultReadOnly;
this.defaultCatalog = defaultCatalog;
this.state = new AtomicInteger();
@@ -93,41 +96,31 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
this.hashCode = System.identityHashCode(this);
isCatalogDirty = true;
+ isReadOnlyDirty = defaultReadOnly;
isAutoCommitDirty = true;
isTransactionIsolationDirty = true;
}
- public final void untrackStatement(Object statement)
- {
- // If the connection is not closed. If it is closed, it means this is being
- // called back as a result of the close() method below in which case we
- // will clear the openStatements collection en mass.
- if (!isClosed)
- {
- openStatements.remove(statement);
- }
- }
-
- public final long getCreationTime()
- {
- return creationTime;
- }
-
- public final long getLastAccess()
+ /** {@inheritDoc} */
+ @Override
+ public final boolean equals(Object other)
{
- return lastAccess;
+ return this == other;
}
- public final void unclose()
+ /** {@inheritDoc} */
+ @Override
+ public final int hashCode()
{
- isClosed = false;
+ return hashCode;
}
- public final void realClose() throws SQLException
- {
- delegate.close();
- }
+ // ***********************************************************************
+ // IHikariConnectionProxy methods
+ // ***********************************************************************
+ /** {@inheritDoc} */
+ @Override
public final void captureStack(long leakDetectionThreshold, Timer scheduler)
{
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
@@ -138,11 +131,8 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
scheduler.schedule(leakTask, leakDetectionThreshold);
}
- public final boolean isBrokenConnection()
- {
- return forceClose;
- }
-
+ /** {@inheritDoc} */
+ @Override
public final void checkException(SQLException sqle)
{
String sqlState = sqle.getSQLState();
@@ -160,33 +150,43 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
}
+ /** {@inheritDoc} */
@Override
- public final boolean equals(Object other)
+ public final long getCreationTime()
{
- return this == other;
+ return creationTime;
}
+ /** {@inheritDoc} */
@Override
- public final int hashCode()
+ public final long getLastAccess()
{
- return hashCode;
+ return lastAccess;
}
- protected final void checkClosed() throws SQLException
+ /** {@inheritDoc} */
+ @Override
+ public long getLastOpenTime()
{
- if (isClosed)
- {
- throw new SQLException("Connection is closed");
- }
+ return uncloseTime;
}
- private T trackStatement(T statement)
+ /** {@inheritDoc} */
+ @Override
+ public final boolean isBrokenConnection()
{
- openStatements.add(statement);
+ return forceClose;
+ }
- return statement;
+ /** {@inheritDoc} */
+ @Override
+ public final void realClose() throws SQLException
+ {
+ delegate.close();
}
+ /** {@inheritDoc} */
+ @Override
public final void resetConnectionState() throws SQLException
{
if (!delegate.getAutoCommit())
@@ -194,6 +194,12 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
delegate.rollback();
}
+ if (isReadOnlyDirty)
+ {
+ delegate.setReadOnly(defaultReadOnly);
+ isReadOnlyDirty = false;
+ }
+
if (isAutoCommitDirty)
{
delegate.setAutoCommit(defaultAutoCommit);
@@ -215,6 +221,46 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
delegate.clearWarnings();
}
+ /** {@inheritDoc} */
+ @Override
+ public final void unclose()
+ {
+ isClosed = false;
+ uncloseTime = System.currentTimeMillis();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final void untrackStatement(Object statement)
+ {
+ // If the connection is not closed. If it is closed, it means this is being
+ // called back as a result of the close() method below in which case we
+ // will clear the openStatements collection en mass.
+ if (!isClosed)
+ {
+ openStatements.remove(statement);
+ }
+ }
+
+ // ***********************************************************************
+ // Internal methods
+ // ***********************************************************************
+
+ protected final void checkClosed() throws SQLException
+ {
+ if (isClosed)
+ {
+ throw new SQLException("Connection is closed");
+ }
+ }
+
+ private T trackStatement(T statement)
+ {
+ openStatements.add(statement);
+
+ return statement;
+ }
+
// **********************************************************************
// IBagManagable Methods
// **********************************************************************
@@ -238,6 +284,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
// **********************************************************************
/** {@inheritDoc} */
+ @Override
public final void close() throws SQLException
{
if (!isClosed)
@@ -253,19 +300,20 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
try
{
final int size = openStatements.size();
- for (int i = 0; i < size; i++)
+ if (size > 0)
{
- try
- {
- openStatements.get(i).close();
- }
- catch (SQLException e)
+ for (int i = 0; i < size; i++)
{
- checkException(e);
+ try
+ {
+ openStatements.get(i).close();
+ }
+ catch (SQLException e)
+ {
+ checkException(e);
+ }
}
- }
- if (size > 0)
- {
+
openStatements.clear();
}
@@ -285,12 +333,14 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final boolean isClosed() throws SQLException
{
return isClosed;
}
/** {@inheritDoc} */
+ @Override
public final Statement createStatement() throws SQLException
{
checkClosed();
@@ -307,6 +357,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
checkClosed();
@@ -323,6 +374,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
checkClosed();
@@ -339,6 +391,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final CallableStatement prepareCall(String sql) throws SQLException
{
checkClosed();
@@ -355,6 +408,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
checkClosed();
@@ -371,6 +425,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
checkClosed();
@@ -387,6 +442,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final PreparedStatement prepareStatement(String sql) throws SQLException
{
checkClosed();
@@ -403,6 +459,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException
{
checkClosed();
@@ -419,6 +476,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
checkClosed();
@@ -435,6 +493,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
checkClosed();
@@ -451,6 +510,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException
{
checkClosed();
@@ -467,6 +527,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException
{
checkClosed();
@@ -483,6 +544,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final boolean isValid(int timeout) throws SQLException
{
if (isClosed)
@@ -502,6 +564,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final void setAutoCommit(boolean autoCommit) throws SQLException
{
checkClosed();
@@ -518,6 +581,24 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
+ public final void setReadOnly(boolean readOnly) throws SQLException
+ {
+ checkClosed();
+ try
+ {
+ delegate.setReadOnly(readOnly);
+ isReadOnlyDirty = (readOnly != defaultReadOnly);
+ }
+ catch (SQLException e)
+ {
+ checkException(e);
+ throw e;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
public final void setTransactionIsolation(int level) throws SQLException
{
checkClosed();
@@ -550,12 +631,14 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
/** {@inheritDoc} */
+ @Override
public final boolean isWrapperFor(Class> iface) throws SQLException
{
return iface.isInstance(delegate);
}
/** {@inheritDoc} */
+ @Override
@SuppressWarnings("unchecked")
public final T unwrap(Class iface) throws SQLException
{
diff --git a/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java b/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java
index 43d35226..5504cb22 100644
--- a/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java
+++ b/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java
@@ -23,26 +23,82 @@ import java.util.Timer;
import com.zaxxer.hikari.util.ConcurrentBag.IBagManagable;
/**
+ * The interface used by the Connection proxy and through which all interaction
+ * by other classes flow.
+ *
* @author Brett Wooldridge
*/
public interface IHikariConnectionProxy extends Connection, IBagManagable
{
- void unclose();
-
- void realClose() throws SQLException;
-
- void untrackStatement(Object statement);
+ /**
+ * Catpure the stack and start leak detection.
+ *
+ * @param leakThreshold the number of milliseconds before a leak is reported
+ * @param houseKeepingTimer the timer to run the leak detection task with
+ */
+ void captureStack(long leakThreshold, Timer houseKeepingTimer);
+ /**
+ * Check if the provided SQLException contains a SQLSTATE that indicates
+ * a disconnection from the server.
+ *
+ * @param sqle the SQLException to check
+ */
void checkException(SQLException sqle);
- boolean isBrokenConnection();
-
+ /**
+ * Get the creation timestamp of the connection.
+ *
+ * @return the creation timestamp
+ */
long getCreationTime();
+ /**
+ * Get the last access timestamp of the connection.
+ *
+ * @return the last access timestamp
+ */
long getLastAccess();
+ /**
+ * Get the timestamp of when the connection was removed from the pool for use.
+ *
+ * @return the timestamp the connection started to be used in the most recent request
+ */
+ long getLastOpenTime();
+
+ /**
+ * Return the broken state of the connection. If checkException() detected
+ * a broken connection, this method will return true, otherwise false.
+ *
+ * @return the broken state of the connection
+ */
+ boolean isBrokenConnection();
+
+ /**
+ * Actually close the underlying delegate Connection.
+ *
+ * @throws SQLException rethrown from the underlying delegate Connection
+ */
+ void realClose() throws SQLException;
+
+ /**
+ * Reset the delegate Connection back to pristine state.
+ *
+ * @throws SQLException thrown if there is an error resetting any of the state
+ */
void resetConnectionState() throws SQLException;
- /* Leak Detection API */
- void captureStack(long leakThreshold, Timer houseKeepingTimer);
+ /**
+ * Make the Connection available for use again by marking it as not closed.
+ */
+ void unclose();
+
+ /**
+ * Called by Statement and its subclasses when they are closed to remove them
+ * from the tracking list.
+ *
+ * @param statement the Statement to remove from tracking
+ */
+ void untrackStatement(Object statement);
}
diff --git a/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java b/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java
index f878a2ef..07dd15f1 100644
--- a/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java
+++ b/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Brett Wooldridge
+ * Copyright (C) 2013, 2014 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,6 +36,10 @@ import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.util.ClassLoaderUtils;
/**
+ * This class generates the proxy objects for {@link Connection}, {@link Statement},
+ * {@link PreparedStatement}, and {@link CallableStatement}. Additionally it injects
+ * method bodies into the {@link ProxyFactory} class methods that can instantiate
+ * instances of the generated proxies.
*
* @author Brett Wooldridge
*/
@@ -45,27 +49,25 @@ public final class JavassistProxyFactory
static
{
- ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
try
{
- Thread.currentThread().setContextClassLoader(JavassistProxyFactory.class.getClassLoader());
-
JavassistProxyFactory proxyFactoryFactory = new JavassistProxyFactory();
proxyFactoryFactory.modifyProxyFactory();
}
catch (Exception e)
{
+ LoggerFactory.getLogger(JavassistProxyFactory.class).error("Fatal exception during proxy generation", e);
throw new RuntimeException(e);
}
- finally
- {
- Thread.currentThread().setContextClassLoader(contextClassLoader);
- }
}
+ /**
+ * Simply invoking this method causes the initialization of this class. All work
+ * by this class is performed in static initialization.
+ */
public static void initialize()
{
- // simply invoking this method causes the initialization of this class.
+ // no-op
}
private JavassistProxyFactory()
@@ -102,30 +104,22 @@ public final class JavassistProxyFactory
for (CtMethod method : proxyCt.getMethods())
{
String methodName = method.getName();
- StringBuilder call = new StringBuilder("{");
if ("getProxyConnection".equals(methodName))
{
- call.append("return new ").append(packageName).append(".ConnectionJavassistProxy($$);");
+ method.setBody("{return new " + packageName + ".ConnectionJavassistProxy($$);}");
}
else if ("getProxyStatement".equals(methodName))
{
- call.append("return new ").append(packageName).append(".StatementJavassistProxy($$);");
+ method.setBody("{return new " + packageName + ".StatementJavassistProxy($$);}");
}
else if ("getProxyPreparedStatement".equals(methodName))
{
- call.append("return new ").append(packageName).append(".PreparedStatementJavassistProxy($$);");
+ method.setBody("{return new " + packageName + ".PreparedStatementJavassistProxy($$);}");
}
else if ("getProxyCallableStatement".equals(methodName))
{
- call.append("return new ").append(packageName).append(".CallableStatementJavassistProxy($$);");
+ method.setBody("{return new " + packageName + ".CallableStatementJavassistProxy($$);}");
}
- else
- {
- continue;
- }
-
- call.append('}');
- method.setBody(call.toString());
}
proxyCt.toClass(classPool.getClassLoader(), null);
diff --git a/src/main/java/com/zaxxer/hikari/proxy/LeakTask.java b/src/main/java/com/zaxxer/hikari/proxy/LeakTask.java
index 4c63a6e0..c2215f47 100644
--- a/src/main/java/com/zaxxer/hikari/proxy/LeakTask.java
+++ b/src/main/java/com/zaxxer/hikari/proxy/LeakTask.java
@@ -23,7 +23,7 @@ import org.slf4j.LoggerFactory;
/**
* @author Brett Wooldridge
*/
-public class LeakTask extends TimerTask
+class LeakTask extends TimerTask
{
private final long leakTime;
private StackTraceElement[] stackTrace;
diff --git a/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java b/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java
index e9ca61ab..33ae93f4 100644
--- a/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java
+++ b/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java
@@ -37,6 +37,7 @@ public abstract class PreparedStatementProxy extends StatementProxy implements P
// **********************************************************************
/** {@inheritDoc} */
+ @Override
public final ResultSet executeQuery() throws SQLException
{
try
diff --git a/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java b/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java
index 06348822..d07f57e7 100644
--- a/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java
+++ b/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Brett Wooldridge
+ * Copyright (C) 2013, 2014 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,13 +24,30 @@ import java.sql.Statement;
import com.zaxxer.hikari.HikariPool;
/**
- * Injected proxy factory class.
+ * A factory class that produces proxies around instances of the standard
+ * JDBC interfaces.
*
* @author Brett Wooldridge
*/
public final class ProxyFactory
{
- public static IHikariConnectionProxy getProxyConnection(HikariPool pool, Connection connection, int defaultIsolationLevel, boolean defaultAutoCommit, String defaultCatalog)
+ private ProxyFactory()
+ {
+ // unconstructable
+ }
+
+ /**
+ * Create a proxy for the specified {@link Connection} instance.
+ *
+ * @param pool the {@link HikariPool} that will own this proxy
+ * @param connection the {@link Connection} that will be wrapped by this proxy
+ * @param defaultIsolationLevel the default transaction isolation level of the underlying {@link Connection}
+ * @param defaultAutoCommit the default auto-commit state of the underlying {@link Connection}
+ * @param defaultIReadOnly the default readOnly state of the underlying {@link Connection}
+ * @param defaultCatalog the default catalog of the underlying {@link Connection}
+ * @return a proxy that wraps the specified {@link Connection}
+ */
+ public static IHikariConnectionProxy getProxyConnection(HikariPool pool, Connection connection, int defaultIsolationLevel, boolean defaultAutoCommit, boolean defaultIReadOnly, String defaultCatalog)
{
// Body is injected by JavassistProxyFactory
return null;
diff --git a/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java b/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java
index a4e125a1..81a86154 100644
--- a/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java
+++ b/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java
@@ -50,6 +50,7 @@ public abstract class StatementProxy implements Statement
// **********************************************************************
/** {@inheritDoc} */
+ @Override
public final void close() throws SQLException
{
if (isClosed)
@@ -72,6 +73,7 @@ public abstract class StatementProxy implements Statement
}
/** {@inheritDoc} */
+ @Override
public final ResultSet executeQuery(String sql) throws SQLException
{
try
@@ -86,6 +88,7 @@ public abstract class StatementProxy implements Statement
}
/** {@inheritDoc} */
+ @Override
public final ResultSet getResultSet() throws SQLException
{
try
@@ -100,6 +103,7 @@ public abstract class StatementProxy implements Statement
}
/** {@inheritDoc} */
+ @Override
public final ResultSet getGeneratedKeys() throws SQLException
{
try
@@ -114,6 +118,7 @@ public abstract class StatementProxy implements Statement
}
/** {@inheritDoc} */
+ @Override
public final Connection getConnection() throws SQLException
{
return connection;
diff --git a/src/main/java/com/zaxxer/hikari/util/ConcurrentBag.java b/src/main/java/com/zaxxer/hikari/util/ConcurrentBag.java
index b3d5586c..e9d21d02 100644
--- a/src/main/java/com/zaxxer/hikari/util/ConcurrentBag.java
+++ b/src/main/java/com/zaxxer/hikari/util/ConcurrentBag.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Brett Wooldridge
+ * Copyright (C) 2013, 2014 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,12 +28,12 @@ import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
* to LinkedBlockingQueue and LinkedTransferQueue for the purposes of a
* connection pool. It uses ThreadLocal storage when possible to avoid
* locks, but resorts to scanning a common collection if there are no
- * available connections in the ThreadLocal list. Idle connections in
- * ThreadLocal lists can be "stolen" when the poll()ing thread has none
+ * available items in the ThreadLocal list. Not-in-use items in the
+ * ThreadLocal lists can be "stolen" when the borrowing thread has none
* of its own. It is a "lock-less" implementation using a specialized
* AbstractQueuedLongSynchronizer to manage cross-thread signaling.
*
- * Note that objects that are "borrowed" from the bag are not actually
+ * Note that items that are "borrowed" from the bag are not actually
* removed from any collection, so garbage collection will not occur
* even if the reference is abandoned. Thus care must be taken to
* "requite" borrowed objects otherwise a memory leak will result. Only
@@ -64,9 +64,18 @@ public class ConcurrentBag>> threadList;
@@ -127,7 +136,7 @@ public class ConcurrentBag(value));
+ LinkedList> list = threadList.get();
+ if (list == null)
+ {
+ list = new LinkedList>();
+ threadList.set(list);
+ }
+
+ list.addLast(new WeakReference(value));
synchronizer.releaseShared(returnTime);
}
else
@@ -180,7 +196,7 @@ public class ConcurrentBag[0]) != null;
+ }
+ catch (Exception e)
+ {
+ // nothing
+ }
+ }
@Override
protected long tryAcquireShared(long startScanTime)
{
- return getState() > startScanTime ? 1 : -1;
+ return getState() >= startScanTime && !java67hasQueuedPredecessors() ? 1 : -1;
}
/** {@inheritDoc} */
@@ -268,5 +351,15 @@ public class ConcurrentBag T unwrap(Class iface) throws SQLException
+ {
+ throw new SQLFeatureNotSupportedException();
+ }
+
+ @Override
+ public boolean isWrapperFor(Class> iface) throws SQLException
+ {
+ return false;
+ }
+
+ public void shutdown()
+ {
+ }
+}
diff --git a/src/main/java/com/zaxxer/hikari/util/FastStatementList.java b/src/main/java/com/zaxxer/hikari/util/FastStatementList.java
index 65eee2fa..fa0de408 100644
--- a/src/main/java/com/zaxxer/hikari/util/FastStatementList.java
+++ b/src/main/java/com/zaxxer/hikari/util/FastStatementList.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Brett Wooldridge
+ * Copyright (C) 2013, 2014 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@ public final class FastStatementList
private int size;
/**
- * Construct a FastList with a default size of 16.
+ * Construct a FastList with a default size of 32.
*/
public FastStatementList()
{
diff --git a/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java b/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java
new file mode 100644
index 00000000..2c67fb43
--- /dev/null
+++ b/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java
@@ -0,0 +1,77 @@
+package com.zaxxer.hikari.util;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+public final class PoolUtilities
+{
+ public static void quietlyCloseConnection(Connection connection)
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (SQLException e)
+ {
+ return;
+ }
+ }
+
+ /**
+ * Execute the user-specified init SQL.
+ *
+ * @param connection the connection to initialize
+ * @throws SQLException throws if the init SQL execution fails
+ */
+ public static void executeSqlAutoCommit(Connection connection, String sql) throws SQLException
+ {
+ if (sql != null)
+ {
+ connection.setAutoCommit(true);
+ Statement statement = connection.createStatement();
+ try
+ {
+ statement.execute(sql);
+ }
+ finally
+ {
+ statement.close();
+ }
+ }
+ }
+
+ public static void quietlySleep(int millis)
+ {
+ try
+ {
+ Thread.sleep(millis);
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static ThreadPoolExecutor createThreadPoolExecutor(final int queueSize, final String threadName)
+ {
+ ThreadFactory threadFactory = new ThreadFactory() {
+ public Thread newThread(Runnable r)
+ {
+ Thread t = new Thread(r, threadName);
+ t.setDaemon(true);
+ return t;
+ }
+ };
+
+ int processors = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
+ LinkedBlockingQueue queue = new LinkedBlockingQueue(queueSize);
+ ThreadPoolExecutor executor = new ThreadPoolExecutor(processors, processors, 10, TimeUnit.SECONDS, queue, threadFactory, new ThreadPoolExecutor.DiscardPolicy());
+ executor.allowCoreThreadTimeOut(true);
+ return executor;
+ }
+}
diff --git a/src/main/java/com/zaxxer/hikari/util/PropertyBeanSetter.java b/src/main/java/com/zaxxer/hikari/util/PropertyBeanSetter.java
index 035823e0..11e3fb25 100644
--- a/src/main/java/com/zaxxer/hikari/util/PropertyBeanSetter.java
+++ b/src/main/java/com/zaxxer/hikari/util/PropertyBeanSetter.java
@@ -61,9 +61,27 @@ public final class PropertyBeanSetter
private static void setProperty(Object target, String propName, Object propValue)
{
String capitalized = "set" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
+ PropertyDescriptor propertyDescriptor;
+ try
+ {
+ propertyDescriptor = new PropertyDescriptor(propName, target.getClass(), null, capitalized);
+ }
+ catch (IntrospectionException e)
+ {
+ capitalized = "set" + propName.toUpperCase();
+ try
+ {
+ propertyDescriptor = new PropertyDescriptor(propName, target.getClass(), null, capitalized);
+ }
+ catch (IntrospectionException e1)
+ {
+ LOGGER.error("Property {} is does not exist on target class {}", propName, target.getClass());
+ throw new RuntimeException(e);
+ }
+ }
+
try
{
- PropertyDescriptor propertyDescriptor = new PropertyDescriptor(propName, target.getClass(), null, capitalized);
Method writeMethod = propertyDescriptor.getWriteMethod();
Class> paramClass = writeMethod.getParameterTypes()[0];
if (paramClass == int.class)
@@ -87,11 +105,6 @@ public final class PropertyBeanSetter
writeMethod.invoke(target, propValue);
}
}
- catch (IntrospectionException e)
- {
- LOGGER.error("Property {} is does not exist on target class {}", propName, target.getClass());
- throw new RuntimeException(e);
- }
catch (Exception e)
{
LOGGER.error("Exception setting property {} on target class {}", propName, target.getClass(), e);
diff --git a/src/test/java/com/zaxxer/hikari/ConnectionStateTest.java b/src/test/java/com/zaxxer/hikari/ConnectionStateTest.java
index 1ded50f2..ba2b581c 100644
--- a/src/test/java/com/zaxxer/hikari/ConnectionStateTest.java
+++ b/src/test/java/com/zaxxer/hikari/ConnectionStateTest.java
@@ -13,9 +13,8 @@ public class ConnectionStateTest
{
HikariDataSource ds = new HikariDataSource();
ds.setAutoCommit(true);
- ds.setMinimumPoolSize(1);
+ ds.setMinimumIdle(1);
ds.setMaximumPoolSize(1);
- ds.setAcquireIncrement(1);
ds.setConnectionTestQuery("VALUES 1");
ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
@@ -41,9 +40,8 @@ public class ConnectionStateTest
{
HikariDataSource ds = new HikariDataSource();
ds.setTransactionIsolation("TRANSACTION_READ_COMMITTED");
- ds.setMinimumPoolSize(1);
+ ds.setMinimumIdle(1);
ds.setMaximumPoolSize(1);
- ds.setAcquireIncrement(1);
ds.setConnectionTestQuery("VALUES 1");
ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
@@ -64,14 +62,25 @@ public class ConnectionStateTest
}
}
+ @Test
+ public void testIsolation() throws Exception
+ {
+ HikariConfig config = new HikariConfig();
+ config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
+ config.setTransactionIsolation("TRANSACTION_REPEATABLE_READ");
+ config.validate();
+
+ int transactionIsolation = config.getTransactionIsolation();
+ Assert.assertSame(Connection.TRANSACTION_REPEATABLE_READ, transactionIsolation);
+ }
+
@Test
public void testCatalog() throws SQLException
{
HikariDataSource ds = new HikariDataSource();
ds.setCatalog("test");
- ds.setMinimumPoolSize(1);
+ ds.setMinimumIdle(1);
ds.setMaximumPoolSize(1);
- ds.setAcquireIncrement(1);
ds.setConnectionTestQuery("VALUES 1");
ds.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
diff --git a/src/test/java/com/zaxxer/hikari/ExceptionTest.java b/src/test/java/com/zaxxer/hikari/ExceptionTest.java
index bd714535..b34afc89 100644
--- a/src/test/java/com/zaxxer/hikari/ExceptionTest.java
+++ b/src/test/java/com/zaxxer/hikari/ExceptionTest.java
@@ -18,9 +18,9 @@ public class ExceptionTest
public void setup()
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(2);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
@@ -91,9 +91,9 @@ public class ExceptionTest
public void testUseAfterClose() throws SQLException
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(2);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
diff --git a/src/test/java/com/zaxxer/hikari/JdbcDriverTest.java b/src/test/java/com/zaxxer/hikari/JdbcDriverTest.java
new file mode 100644
index 00000000..6892d034
--- /dev/null
+++ b/src/test/java/com/zaxxer/hikari/JdbcDriverTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Brett Wooldridge
+ *
+ * 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.zaxxer.hikari;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import org.junit.Assert;
+
+import org.junit.Test;
+
+import com.zaxxer.hikari.util.DriverDataSource;
+
+public class JdbcDriverTest
+{
+ @Test
+ public void driverTest1() throws SQLException
+ {
+ HikariConfig config = new HikariConfig();
+ config.setMinimumIdle(1);
+ config.setMaximumPoolSize(1);
+ config.setConnectionTestQuery("VALUES 1");
+ config.setDriverClassName("com.zaxxer.hikari.mocks.StubDriver");
+ config.setJdbcUrl("jdbc:stub");
+ config.addDataSourceProperty("user", "bart");
+ config.addDataSourceProperty("password", "simpson");
+
+ HikariDataSource ds = new HikariDataSource(config);
+
+ Assert.assertTrue(ds.isWrapperFor(DriverDataSource.class));
+
+ DriverDataSource unwrap = ds.unwrap(DriverDataSource.class);
+ Assert.assertNotNull(unwrap);
+
+ Connection connection = ds.getConnection();
+ connection.close();
+ ds.shutdown();
+ }
+}
diff --git a/src/test/java/com/zaxxer/hikari/RampUpDown.java b/src/test/java/com/zaxxer/hikari/RampUpDown.java
index 02fcc2fc..03cfbb33 100644
--- a/src/test/java/com/zaxxer/hikari/RampUpDown.java
+++ b/src/test/java/com/zaxxer/hikari/RampUpDown.java
@@ -12,9 +12,9 @@ public class RampUpDown
public void rampUpDownTest() throws SQLException, InterruptedException
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(5);
+ config.setMinimumIdle(5);
config.setMaximumPoolSize(60);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
diff --git a/src/test/java/com/zaxxer/hikari/StatementTest.java b/src/test/java/com/zaxxer/hikari/StatementTest.java
index 9a458403..d35ee984 100644
--- a/src/test/java/com/zaxxer/hikari/StatementTest.java
+++ b/src/test/java/com/zaxxer/hikari/StatementTest.java
@@ -13,9 +13,9 @@ public class StatementTest
public void testStatementClose() throws SQLException
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(2);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
@@ -42,9 +42,9 @@ public class StatementTest
public void testAutoStatementClose() throws SQLException
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(2);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
@@ -67,9 +67,9 @@ public class StatementTest
public void testDoubleStatementClose() throws SQLException
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(2);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
@@ -88,9 +88,9 @@ public class StatementTest
public void testOutOfOrderStatementClose() throws SQLException
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(2);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
diff --git a/src/test/java/com/zaxxer/hikari/TestConnectionTimeoutRetry.java b/src/test/java/com/zaxxer/hikari/TestConnectionTimeoutRetry.java
new file mode 100644
index 00000000..d1c97a98
--- /dev/null
+++ b/src/test/java/com/zaxxer/hikari/TestConnectionTimeoutRetry.java
@@ -0,0 +1,270 @@
+package com.zaxxer.hikari;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.zaxxer.hikari.mocks.StubDataSource;
+
+public class TestConnectionTimeoutRetry
+{
+ @Test
+ public void testConnectionRetries() throws SQLException
+ {
+ HikariConfig config = new HikariConfig();
+ config.setMinimumIdle(0);
+ config.setMaximumPoolSize(1);
+ config.setConnectionTimeout(2800);
+ config.setConnectionTestQuery("VALUES 1");
+ config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
+
+ HikariDataSource ds = new HikariDataSource(config);
+
+ StubDataSource stubDataSource = ds.unwrap(StubDataSource.class);
+ stubDataSource.setThrowException(new SQLException("Connection refused"));
+
+ long start = System.currentTimeMillis();
+ try
+ {
+ Connection connection = ds.getConnection();
+ connection.close();
+ Assert.fail("Should not have been able to get a connection.");
+ }
+ catch (SQLException e)
+ {
+ long elapsed = System.currentTimeMillis() - start;
+ long timeout = config.getConnectionTimeout();
+ Assert.assertTrue("Didn't wait long enough for timeout", (elapsed >= timeout));
+ }
+ finally
+ {
+ ds.shutdown();
+ }
+ }
+
+ @Test
+ public void testConnectionRetries2() throws SQLException
+ {
+ HikariConfig config = new HikariConfig();
+ config.setMinimumIdle(0);
+ config.setMaximumPoolSize(1);
+ config.setConnectionTimeout(2800);
+ config.setInitializationFailFast(true);
+ config.setConnectionTestQuery("VALUES 1");
+ config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
+
+ HikariDataSource ds = new HikariDataSource(config);
+
+ final StubDataSource stubDataSource = ds.unwrap(StubDataSource.class);
+ stubDataSource.setThrowException(new SQLException("Connection refused"));
+
+ ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+ scheduler.schedule(new Runnable() {
+ public void run()
+ {
+ stubDataSource.setThrowException(null);
+ }
+ }, 300, TimeUnit.MILLISECONDS);
+
+ long start = System.currentTimeMillis();
+ try
+ {
+ Connection connection = ds.getConnection();
+ connection.close();
+
+ long elapsed = System.currentTimeMillis() - start;
+ Assert.assertTrue("Connection returned too quickly, something is wrong.", elapsed > 250);
+ Assert.assertTrue("Waited too long to get a connection.", elapsed < config.getConnectionTimeout());
+ }
+ catch (SQLException e)
+ {
+ Assert.fail("Should not have timed out.");
+ }
+ finally
+ {
+ scheduler.shutdownNow();
+ ds.shutdown();
+ }
+ }
+
+ @Test
+ public void testConnectionRetries3() throws SQLException
+ {
+ HikariConfig config = new HikariConfig();
+ config.setMinimumIdle(0);
+ config.setMaximumPoolSize(2);
+ config.setConnectionTimeout(2800);
+ config.setConnectionTestQuery("VALUES 1");
+ config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
+
+ HikariDataSource ds = new HikariDataSource(config);
+
+ final Connection connection1 = ds.getConnection();
+ final Connection connection2 = ds.getConnection();
+ Assert.assertNotNull(connection1);
+ Assert.assertNotNull(connection2);
+
+ ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
+ scheduler.schedule(new Runnable() {
+ public void run()
+ {
+ try
+ {
+ connection1.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(System.err);
+ }
+ }
+ }, 800, TimeUnit.MILLISECONDS);
+
+ long start = System.currentTimeMillis();
+ try
+ {
+ Connection connection3 = ds.getConnection();
+ connection3.close();
+
+ long elapsed = System.currentTimeMillis() - start;
+ Assert.assertTrue("Waited too long to get a connection.", (elapsed >= 700) && (elapsed < 950));
+ }
+ catch (SQLException e)
+ {
+ Assert.fail("Should not have timed out.");
+ }
+ finally
+ {
+ scheduler.shutdownNow();
+ ds.shutdown();
+ }
+ }
+
+ @Test
+ public void testConnectionRetries4() throws SQLException
+ {
+ HikariConfig config = new HikariConfig();
+ config.setMinimumIdle(0);
+ config.setMaximumPoolSize(1);
+ config.setConnectionTimeout(1000);
+ config.setConnectionTestQuery("VALUES 1");
+ config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
+
+ HikariDataSource ds = new HikariDataSource(config);
+
+ StubDataSource stubDataSource = ds.unwrap(StubDataSource.class);
+ stubDataSource.setThrowException(new SQLException("Connection refused"));
+
+ long start = System.currentTimeMillis();
+ try
+ {
+ Connection connection = ds.getConnection();
+ connection.close();
+ Assert.fail("Should not have been able to get a connection.");
+ }
+ catch (SQLException e)
+ {
+ long elapsed = System.currentTimeMillis() - start;
+ Assert.assertTrue("Didn't wait long enough for timeout", (elapsed >= config.getConnectionTimeout()));
+ }
+ finally
+ {
+ ds.shutdown();
+ }
+ }
+
+
+ @Test
+ public void testConnectionRetries5() throws SQLException
+ {
+ HikariConfig config = new HikariConfig();
+ config.setMinimumIdle(0);
+ config.setMaximumPoolSize(2);
+ config.setConnectionTimeout(1000);
+ config.setConnectionTestQuery("VALUES 1");
+ config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
+
+ HikariDataSource ds = new HikariDataSource(config);
+
+ final Connection connection1 = ds.getConnection();
+
+ long start = System.currentTimeMillis();
+
+ ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
+ scheduler.schedule(new Runnable() {
+ public void run()
+ {
+ try
+ {
+ connection1.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(System.err);
+ }
+ }
+ }, 250, TimeUnit.MILLISECONDS);
+
+ StubDataSource stubDataSource = ds.unwrap(StubDataSource.class);
+ stubDataSource.setThrowException(new SQLException("Connection refused"));
+
+ try
+ {
+ Connection connection2 = ds.getConnection();
+ connection2.close();
+
+ long elapsed = System.currentTimeMillis() - start;
+ Assert.assertTrue("Waited too long to get a connection.", (elapsed >= 250) && (elapsed < config.getConnectionTimeout()));
+ }
+ catch (SQLException e)
+ {
+ Assert.fail("Should not have timed out.");
+ }
+ finally
+ {
+ scheduler.shutdownNow();
+ ds.shutdown();
+ }
+ }
+
+ @Test
+ public void testConnectionIdleFill() throws Exception
+ {
+ HikariConfig config = new HikariConfig();
+ config.setMinimumIdle(5);
+ config.setMaximumPoolSize(10);
+ config.setConnectionTimeout(1000);
+ config.setConnectionTestQuery("VALUES 1");
+ config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
+
+ HikariDataSource ds = new HikariDataSource(config);
+
+ Connection connection1 = ds.getConnection();
+ Connection connection2 = ds.getConnection();
+ Connection connection3 = ds.getConnection();
+ Connection connection4 = ds.getConnection();
+ Connection connection5 = ds.getConnection();
+ Connection connection6 = ds.getConnection();
+ Connection connection7 = ds.getConnection();
+
+ Thread.sleep(1000);
+
+ Assert.assertSame("Totals connections not as expected", 10, ds.pool.getTotalConnections());
+ Assert.assertSame("Idle connections not as expected", 3, ds.pool.getIdleConnections());
+
+ connection1.close();
+ connection2.close();
+ connection3.close();
+ connection4.close();
+ connection5.close();
+ connection6.close();
+ connection7.close();
+
+ Assert.assertSame("Totals connections not as expected", 10, ds.pool.getTotalConnections());
+ Assert.assertSame("Idle connections not as expected", 10, ds.pool.getIdleConnections());
+ }
+}
diff --git a/src/test/java/com/zaxxer/hikari/CreationTest.java b/src/test/java/com/zaxxer/hikari/TestConnections.java
similarity index 79%
rename from src/test/java/com/zaxxer/hikari/CreationTest.java
rename to src/test/java/com/zaxxer/hikari/TestConnections.java
index 309d698e..3f3e03dd 100644
--- a/src/test/java/com/zaxxer/hikari/CreationTest.java
+++ b/src/test/java/com/zaxxer/hikari/TestConnections.java
@@ -24,6 +24,8 @@ import java.sql.SQLException;
import org.junit.Assert;
import org.junit.Test;
+import com.zaxxer.hikari.mocks.StubConnection;
+
/**
* System property testProxy can be one of:
* "com.zaxxer.hikari.JavaProxyFactory"
@@ -32,15 +34,15 @@ import org.junit.Test;
*
* @author Brett Wooldridge
*/
-public class CreationTest
+public class TestConnections
{
@Test
public void testCreate() throws SQLException
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
@@ -83,9 +85,9 @@ public class CreationTest
public void testMaxLifetime() throws Exception
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
@@ -113,10 +115,12 @@ public class CreationTest
Connection connection2 = ds.getConnection();
Assert.assertSame("Expected the same connection", connection, connection2);
+ Assert.assertSame("Second total connections not as expected", 1, ds.pool.getTotalConnections());
+ Assert.assertSame("Second idle connections not as expected", 0, ds.pool.getIdleConnections());
connection2.close();
-
+
Thread.sleep(2000);
-
+
connection2 = ds.getConnection();
Assert.assertNotSame("Expected a different connection", connection, connection2);
@@ -135,9 +139,9 @@ public class CreationTest
public void testDoubleClose() throws Exception
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
@@ -158,9 +162,10 @@ public class CreationTest
public void testBackfill() throws Exception
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(4);
config.setConnectionTimeout(500);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
@@ -199,12 +204,8 @@ public class CreationTest
Assert.assertSame("Totals connections not as expected", 0, ds.pool.getTotalConnections());
Assert.assertSame("Idle connections not as expected", 0, ds.pool.getIdleConnections());
- // This will create a new connection, and cause a backfill
+ // This will cause a backfill
connection = ds.getConnection();
-
- // Wait for scheduled backfill to execute
- Thread.sleep(600);
-
connection.close();
Assert.assertSame("Totals connections not as expected", 1, ds.pool.getTotalConnections());
@@ -217,14 +218,50 @@ public class CreationTest
}
@Test
- public void testIsolation() throws Exception
+ public void testMaximumPoolLimit() throws Exception
{
HikariConfig config = new HikariConfig();
+ config.setMinimumIdle(1);
+ config.setMaximumPoolSize(4);
+ config.setInitializationFailFast(true);
+ config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
- config.setTransactionIsolation("TRANSACTION_REPEATABLE_READ");
- config.validate();
-
- int transactionIsolation = config.getTransactionIsolation();
- Assert.assertSame(Connection.TRANSACTION_REPEATABLE_READ, transactionIsolation);
+
+ StubConnection.count.set(0);
+
+ final HikariDataSource ds = new HikariDataSource(config);
+
+ Thread[] threads = new Thread[20];
+ for (int i = 0; i < threads.length; i++)
+ {
+ threads[i] = new Thread(new Runnable() {
+ public void run()
+ {
+ try
+ {
+ Connection connection = ds.getConnection();
+ Thread.sleep(1000);
+ connection.close();
+ }
+ catch (Exception e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+ for (int i = 0; i < threads.length; i++)
+ {
+ threads[i].start();
+ }
+
+ for (int i = 0; i < threads.length; i++)
+ {
+ threads[i].join();
+ }
+
+ Assert.assertEquals(4, StubConnection.count.get());
}
}
diff --git a/src/test/java/com/zaxxer/hikari/TestPropertySetter.java b/src/test/java/com/zaxxer/hikari/TestPropertySetter.java
index 0df672d3..41169866 100644
--- a/src/test/java/com/zaxxer/hikari/TestPropertySetter.java
+++ b/src/test/java/com/zaxxer/hikari/TestPropertySetter.java
@@ -20,7 +20,7 @@ public class TestPropertySetter
HikariConfig config = new HikariConfig(file.getPath());
config.validate();
- Assert.assertEquals(5, config.getAcquireRetries());
+ Assert.assertEquals(5, config.getMinimumIdle());
Assert.assertEquals("SELECT 1", config.getConnectionTestQuery());
}
@@ -50,4 +50,17 @@ public class TestPropertySetter
Assert.assertSame(PrintWriter.class, dataSource.getLogWriter().getClass());
}
+
+ @Test
+ public void testPropertyUpperCase() throws Exception
+ {
+ File file = new File("src/test/resources/propfile3.properties");
+ HikariConfig config = new HikariConfig(file.getPath());
+ config.validate();
+
+ Class> clazz = this.getClass().getClassLoader().loadClass(config.getDataSourceClassName());
+ DataSource dataSource = (DataSource) clazz.newInstance();
+ PropertyBeanSetter.setTargetFromProperties(dataSource, config.getDataSourceProperties());
+ }
+
}
diff --git a/src/test/java/com/zaxxer/hikari/UnwrapTest.java b/src/test/java/com/zaxxer/hikari/UnwrapTest.java
index 632c7b2f..914a9a09 100644
--- a/src/test/java/com/zaxxer/hikari/UnwrapTest.java
+++ b/src/test/java/com/zaxxer/hikari/UnwrapTest.java
@@ -34,9 +34,9 @@ public class UnwrapTest
public void testUnwrapConnection() throws SQLException
{
HikariConfig config = new HikariConfig();
- config.setMinimumPoolSize(1);
+ config.setMinimumIdle(1);
config.setMaximumPoolSize(1);
- config.setAcquireIncrement(1);
+ config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
diff --git a/src/test/java/com/zaxxer/hikari/mocks/MockDataSource.java b/src/test/java/com/zaxxer/hikari/mocks/MockDataSource.java
index 407f26be..02e1dcc3 100644
--- a/src/test/java/com/zaxxer/hikari/mocks/MockDataSource.java
+++ b/src/test/java/com/zaxxer/hikari/mocks/MockDataSource.java
@@ -44,29 +44,35 @@ import org.mockito.stubbing.Answer;
*/
public class MockDataSource implements DataSource
{
+ @Override
public Connection getConnection() throws SQLException
{
return createMockConnection();
}
+ @Override
public Connection getConnection(String username, String password) throws SQLException
{
return getConnection();
}
+ @Override
public PrintWriter getLogWriter() throws SQLException
{
return null;
}
+ @Override
public void setLogWriter(PrintWriter out) throws SQLException
{
}
+ @Override
public void setLoginTimeout(int seconds) throws SQLException
{
}
+ @Override
public int getLoginTimeout() throws SQLException
{
return 0;
@@ -77,11 +83,13 @@ public class MockDataSource implements DataSource
return null;
}
+ @Override
public T unwrap(Class iface) throws SQLException
{
return null;
}
+ @Override
public boolean isWrapperFor(Class> iface) throws SQLException
{
return false;
@@ -110,6 +118,7 @@ public class MockDataSource implements DataSource
when(mockConnection.prepareStatement(anyString(), anyInt(), anyInt())).thenReturn(mockPreparedStatement);
when(mockConnection.prepareStatement(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(mockPreparedStatement);
doAnswer(new Answer() {
+ @Override
public Void answer(InvocationOnMock invocation) throws Throwable
{
return null;
diff --git a/src/test/java/com/zaxxer/hikari/mocks/StubBaseConnection.java b/src/test/java/com/zaxxer/hikari/mocks/StubBaseConnection.java
index cd7f8989..ee1d64eb 100644
--- a/src/test/java/com/zaxxer/hikari/mocks/StubBaseConnection.java
+++ b/src/test/java/com/zaxxer/hikari/mocks/StubBaseConnection.java
@@ -8,12 +8,14 @@ import java.sql.Statement;
public abstract class StubBaseConnection implements Connection
{
/** {@inheritDoc} */
+ @Override
public Statement createStatement() throws SQLException
{
return new StubStatement(this);
}
/** {@inheritDoc} */
+ @Override
public PreparedStatement prepareStatement(String sql) throws SQLException
{
return new StubPreparedStatement(this);
diff --git a/src/test/java/com/zaxxer/hikari/mocks/StubConnection.java b/src/test/java/com/zaxxer/hikari/mocks/StubConnection.java
index f020cb0c..c5845715 100644
--- a/src/test/java/com/zaxxer/hikari/mocks/StubConnection.java
+++ b/src/test/java/com/zaxxer/hikari/mocks/StubConnection.java
@@ -34,6 +34,7 @@ import java.sql.Struct;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
/**
*
@@ -41,6 +42,8 @@ import java.util.concurrent.Executor;
*/
public class StubConnection extends StubBaseConnection implements Connection
{
+ public static AtomicInteger count = new AtomicInteger();
+
private static long foo;
private boolean autoCommit;
private int isolation;
@@ -51,275 +54,327 @@ public class StubConnection extends StubBaseConnection implements Connection
foo = System.currentTimeMillis();
}
+ public StubConnection()
+ {
+ count.incrementAndGet();
+ }
+
/** {@inheritDoc} */
+ @Override
public T unwrap(Class iface) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public boolean isWrapperFor(Class> iface) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public CallableStatement prepareCall(String sql) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public String nativeSQL(String sql) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void setAutoCommit(boolean autoCommit) throws SQLException
{
this.autoCommit = autoCommit;
}
/** {@inheritDoc} */
+ @Override
public boolean getAutoCommit() throws SQLException
{
return autoCommit;
}
/** {@inheritDoc} */
+ @Override
public void commit() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void rollback() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void close() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public boolean isClosed() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public DatabaseMetaData getMetaData() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void setReadOnly(boolean readOnly) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public boolean isReadOnly() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public void setCatalog(String catalog) throws SQLException
{
this.catalog = catalog;
}
/** {@inheritDoc} */
+ @Override
public String getCatalog() throws SQLException
{
return catalog;
}
/** {@inheritDoc} */
+ @Override
public void setTransactionIsolation(int level) throws SQLException
{
this.isolation = level;
}
/** {@inheritDoc} */
+ @Override
public int getTransactionIsolation() throws SQLException
{
return isolation;
}
/** {@inheritDoc} */
+ @Override
public SQLWarning getWarnings() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void clearWarnings() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
return new StubPreparedStatement(this);
}
/** {@inheritDoc} */
+ @Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Map> getTypeMap() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void setTypeMap(Map> map) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setHoldability(int holdability) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public int getHoldability() throws SQLException
{
return (int) foo;
}
/** {@inheritDoc} */
+ @Override
public Savepoint setSavepoint() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Savepoint setSavepoint(String name) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void rollback(Savepoint savepoint) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
return new StubPreparedStatement(this);
}
/** {@inheritDoc} */
+ @Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException
{
return new StubPreparedStatement(this);
}
/** {@inheritDoc} */
+ @Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException
{
return new StubPreparedStatement(this);
}
/** {@inheritDoc} */
+ @Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException
{
return new StubPreparedStatement(this);
}
/** {@inheritDoc} */
+ @Override
public Clob createClob() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Blob createBlob() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public NClob createNClob() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public SQLXML createSQLXML() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public boolean isValid(int timeout) throws SQLException
{
return true;
}
/** {@inheritDoc} */
+ @Override
public void setClientInfo(String name, String value) throws SQLClientInfoException
{
}
/** {@inheritDoc} */
+ @Override
public void setClientInfo(Properties properties) throws SQLClientInfoException
{
}
/** {@inheritDoc} */
+ @Override
public String getClientInfo(String name) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Properties getClientInfo() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException
{
return null;
diff --git a/src/test/java/com/zaxxer/hikari/mocks/StubDataSource.java b/src/test/java/com/zaxxer/hikari/mocks/StubDataSource.java
index d20d3516..d7e7c936 100644
--- a/src/test/java/com/zaxxer/hikari/mocks/StubDataSource.java
+++ b/src/test/java/com/zaxxer/hikari/mocks/StubDataSource.java
@@ -33,6 +33,7 @@ public class StubDataSource implements DataSource
private String user;
private String password;
private PrintWriter logWriter;
+ private SQLException throwException;
public String getUser()
{
@@ -54,24 +55,33 @@ public class StubDataSource implements DataSource
this.password = password;
}
+ public void setURL(String url)
+ {
+ // we don't care
+ }
+
/** {@inheritDoc} */
+ @Override
public PrintWriter getLogWriter() throws SQLException
{
return logWriter;
}
/** {@inheritDoc} */
+ @Override
public void setLogWriter(PrintWriter out) throws SQLException
{
this.logWriter = out;
}
/** {@inheritDoc} */
+ @Override
public void setLoginTimeout(int seconds) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public int getLoginTimeout() throws SQLException
{
return 0;
@@ -84,26 +94,40 @@ public class StubDataSource implements DataSource
}
/** {@inheritDoc} */
+ @Override
public T unwrap(Class iface) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public boolean isWrapperFor(Class> iface) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public Connection getConnection() throws SQLException
{
+ if (throwException != null)
+ {
+ throw throwException;
+ }
+
return new StubConnection();
}
/** {@inheritDoc} */
+ @Override
public Connection getConnection(String username, String password) throws SQLException
{
return new StubConnection();
}
+
+ public void setThrowException(SQLException e)
+ {
+ this.throwException = e;
+ }
}
diff --git a/src/test/java/com/zaxxer/hikari/mocks/StubDriver.java b/src/test/java/com/zaxxer/hikari/mocks/StubDriver.java
index aff1bfae..aa453df3 100644
--- a/src/test/java/com/zaxxer/hikari/mocks/StubDriver.java
+++ b/src/test/java/com/zaxxer/hikari/mocks/StubDriver.java
@@ -47,36 +47,42 @@ public class StubDriver implements Driver
}
/** {@inheritDoc} */
+ @Override
public Connection connect(String url, Properties info) throws SQLException
{
return new StubConnection();
}
/** {@inheritDoc} */
+ @Override
public boolean acceptsURL(String url) throws SQLException
{
return true;
}
/** {@inheritDoc} */
+ @Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public int getMajorVersion()
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public int getMinorVersion()
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public boolean jdbcCompliant()
{
return true;
diff --git a/src/test/java/com/zaxxer/hikari/mocks/StubPreparedStatement.java b/src/test/java/com/zaxxer/hikari/mocks/StubPreparedStatement.java
index 0046580f..5d6e91a3 100644
--- a/src/test/java/com/zaxxer/hikari/mocks/StubPreparedStatement.java
+++ b/src/test/java/com/zaxxer/hikari/mocks/StubPreparedStatement.java
@@ -51,95 +51,112 @@ public class StubPreparedStatement extends StubStatement implements PreparedStat
}
/** {@inheritDoc} */
+ @Override
public ResultSet executeQuery(String sql) throws SQLException
{
return new StubResultSet();
}
/** {@inheritDoc} */
+ @Override
public int executeUpdate(String sql) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public int getMaxFieldSize() throws SQLException
{
throw new SQLException("No reason", "08999");
}
/** {@inheritDoc} */
+ @Override
public void setMaxFieldSize(int max) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public int getMaxRows() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public void setMaxRows(int max) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setEscapeProcessing(boolean enable) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public int getQueryTimeout() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public void setQueryTimeout(int seconds) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void cancel() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public SQLWarning getWarnings() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void clearWarnings() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setCursorName(String name) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public boolean execute(String sql) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public ResultSet getResultSet() throws SQLException
{
return new StubResultSet();
}
/** {@inheritDoc} */
+ @Override
public int getUpdateCount() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public boolean getMoreResults() throws SQLException
{
if (isClosed())
@@ -150,419 +167,498 @@ public class StubPreparedStatement extends StubStatement implements PreparedStat
}
/** {@inheritDoc} */
+ @Override
public void setFetchDirection(int direction) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public int getFetchDirection() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public void setFetchSize(int rows) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public int getFetchSize() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public int getResultSetConcurrency() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public int getResultSetType() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public void addBatch(String sql) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void clearBatch() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public int[] executeBatch() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public boolean getMoreResults(int current) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public ResultSet getGeneratedKeys() throws SQLException
{
return new StubResultSet();
}
/** {@inheritDoc} */
+ @Override
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean execute(String sql, String[] columnNames) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public int getResultSetHoldability() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public void setPoolable(boolean poolable) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public boolean isPoolable() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public void closeOnCompletion() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public boolean isCloseOnCompletion() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public T unwrap(Class iface) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public boolean isWrapperFor(Class> iface) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public ResultSet executeQuery() throws SQLException
{
return new StubResultSet();
}
/** {@inheritDoc} */
+ @Override
public int executeUpdate() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public void setNull(int parameterIndex, int sqlType) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setBoolean(int parameterIndex, boolean x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setByte(int parameterIndex, byte x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setShort(int parameterIndex, short x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setInt(int parameterIndex, int x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setLong(int parameterIndex, long x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setFloat(int parameterIndex, float x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setDouble(int parameterIndex, double x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setString(int parameterIndex, String x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setBytes(int parameterIndex, byte[] x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setDate(int parameterIndex, Date x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setTime(int parameterIndex, Time x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void clearParameters() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setObject(int parameterIndex, Object x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public boolean execute() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public void addBatch() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setRef(int parameterIndex, Ref x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setBlob(int parameterIndex, Blob x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setClob(int parameterIndex, Clob x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setArray(int parameterIndex, Array x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public ResultSetMetaData getMetaData() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setURL(int parameterIndex, URL x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public ParameterMetaData getParameterMetaData() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void setRowId(int parameterIndex, RowId x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setNString(int parameterIndex, String value) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setNClob(int parameterIndex, NClob value) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setClob(int parameterIndex, Reader reader, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setClob(int parameterIndex, Reader reader) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void setNClob(int parameterIndex, Reader reader) throws SQLException
{
}
diff --git a/src/test/java/com/zaxxer/hikari/mocks/StubResultSet.java b/src/test/java/com/zaxxer/hikari/mocks/StubResultSet.java
index 4cb05695..a4131489 100644
--- a/src/test/java/com/zaxxer/hikari/mocks/StubResultSet.java
+++ b/src/test/java/com/zaxxer/hikari/mocks/StubResultSet.java
@@ -48,6 +48,7 @@ public class StubResultSet implements ResultSet
private boolean closed;
/** {@inheritDoc} */
+ @Override
public T unwrap(Class iface) throws SQLException
{
@@ -55,1035 +56,1223 @@ public class StubResultSet implements ResultSet
}
/** {@inheritDoc} */
+ @Override
public boolean isWrapperFor(Class> iface) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean next() throws SQLException
{
return (counter > 100000);
}
/** {@inheritDoc} */
+ @Override
public void close() throws SQLException
{
closed = true;
}
/** {@inheritDoc} */
+ @Override
public boolean wasNull() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public String getString(int columnIndex) throws SQLException
{
return "aString";
}
/** {@inheritDoc} */
+ @Override
public boolean getBoolean(int columnIndex) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public byte getByte(int columnIndex) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public short getShort(int columnIndex) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public int getInt(int columnIndex) throws SQLException
{
return ++counter;
}
/** {@inheritDoc} */
+ @Override
public long getLong(int columnIndex) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public float getFloat(int columnIndex) throws SQLException
{
throw new SQLException("No reason", "08999");
}
/** {@inheritDoc} */
+ @Override
public double getDouble(int columnIndex) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public byte[] getBytes(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Date getDate(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Time getTime(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Timestamp getTimestamp(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public InputStream getAsciiStream(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public InputStream getUnicodeStream(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public InputStream getBinaryStream(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public String getString(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public boolean getBoolean(String columnLabel) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public byte getByte(String columnLabel) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public short getShort(String columnLabel) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public int getInt(String columnLabel) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public long getLong(String columnLabel) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public float getFloat(String columnLabel) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public double getDouble(String columnLabel) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public byte[] getBytes(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Date getDate(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Time getTime(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Timestamp getTimestamp(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public InputStream getAsciiStream(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public InputStream getUnicodeStream(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public InputStream getBinaryStream(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public SQLWarning getWarnings() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void clearWarnings() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public String getCursorName() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public ResultSetMetaData getMetaData() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Object getObject(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Object getObject(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public int findColumn(String columnLabel) throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public Reader getCharacterStream(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Reader getCharacterStream(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public BigDecimal getBigDecimal(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public BigDecimal getBigDecimal(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public boolean isBeforeFirst() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean isAfterLast() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean isFirst() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean isLast() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public void beforeFirst() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void afterLast() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public boolean first() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean last() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public int getRow() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public boolean absolute(int row) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean relative(int rows) throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean previous() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public void setFetchDirection(int direction) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public int getFetchDirection() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public void setFetchSize(int rows) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public int getFetchSize() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public int getType() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public int getConcurrency() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public boolean rowUpdated() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean rowInserted() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public boolean rowDeleted() throws SQLException
{
return false;
}
/** {@inheritDoc} */
+ @Override
public void updateNull(int columnIndex) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBoolean(int columnIndex, boolean x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateByte(int columnIndex, byte x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateShort(int columnIndex, short x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateInt(int columnIndex, int x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateLong(int columnIndex, long x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateFloat(int columnIndex, float x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateDouble(int columnIndex, double x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateString(int columnIndex, String x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBytes(int columnIndex, byte[] x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateDate(int columnIndex, Date x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateTime(int columnIndex, Time x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateObject(int columnIndex, Object x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNull(String columnLabel) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBoolean(String columnLabel, boolean x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateByte(String columnLabel, byte x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateShort(String columnLabel, short x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateInt(String columnLabel, int x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateLong(String columnLabel, long x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateFloat(String columnLabel, float x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateDouble(String columnLabel, double x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateString(String columnLabel, String x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBytes(String columnLabel, byte[] x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateDate(String columnLabel, Date x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateTime(String columnLabel, Time x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateObject(String columnLabel, Object x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void insertRow() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateRow() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void deleteRow() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void refreshRow() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void cancelRowUpdates() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void moveToInsertRow() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void moveToCurrentRow() throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public Statement getStatement() throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Object getObject(int columnIndex, Map> map) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Ref getRef(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Blob getBlob(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Clob getClob(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Array getArray(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Object getObject(String columnLabel, Map> map) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Ref getRef(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Blob getBlob(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Clob getClob(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Array getArray(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Date getDate(int columnIndex, Calendar cal) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Date getDate(String columnLabel, Calendar cal) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Time getTime(int columnIndex, Calendar cal) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Time getTime(String columnLabel, Calendar cal) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public URL getURL(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public URL getURL(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void updateRef(int columnIndex, Ref x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateRef(String columnLabel, Ref x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBlob(int columnIndex, Blob x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBlob(String columnLabel, Blob x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateClob(int columnIndex, Clob x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateClob(String columnLabel, Clob x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateArray(int columnIndex, Array x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateArray(String columnLabel, Array x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public RowId getRowId(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public RowId getRowId(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void updateRowId(int columnIndex, RowId x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateRowId(String columnLabel, RowId x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public int getHoldability() throws SQLException
{
return 0;
}
/** {@inheritDoc} */
+ @Override
public boolean isClosed() throws SQLException
{
return closed;
}
/** {@inheritDoc} */
+ @Override
public void updateNString(int columnIndex, String nString) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNString(String columnLabel, String nString) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNClob(int columnIndex, NClob nClob) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNClob(String columnLabel, NClob nClob) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public NClob getNClob(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public NClob getNClob(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public SQLXML getSQLXML(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public SQLXML getSQLXML(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public String getNString(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public String getNString(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Reader getNCharacterStream(int columnIndex) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public Reader getNCharacterStream(String columnLabel) throws SQLException
{
return null;
}
/** {@inheritDoc} */
+ @Override
public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateClob(int columnIndex, Reader reader, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateClob(String columnLabel, Reader reader, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateCharacterStream(int columnIndex, Reader x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateClob(int columnIndex, Reader reader) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateClob(String columnLabel, Reader reader) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNClob(int columnIndex, Reader reader) throws SQLException
{
}
/** {@inheritDoc} */
+ @Override
public void updateNClob(String columnLabel, Reader reader) throws SQLException
{
}
diff --git a/src/test/java/com/zaxxer/hikari/mocks/StubStatement.java b/src/test/java/com/zaxxer/hikari/mocks/StubStatement.java
index 5db6c618..335bb366 100644
--- a/src/test/java/com/zaxxer/hikari/mocks/StubStatement.java
+++ b/src/test/java/com/zaxxer/hikari/mocks/StubStatement.java
@@ -37,6 +37,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public T unwrap(Class iface) throws SQLException
{
checkClosed();
@@ -44,6 +45,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public boolean isWrapperFor(Class> iface) throws SQLException
{
checkClosed();
@@ -51,6 +53,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public ResultSet executeQuery(String sql) throws SQLException
{
checkClosed();
@@ -59,6 +62,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public int executeUpdate(String sql) throws SQLException
{
checkClosed();
@@ -66,12 +70,14 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public void close() throws SQLException
{
closed = true;
}
/** {@inheritDoc} */
+ @Override
public int getMaxFieldSize() throws SQLException
{
checkClosed();
@@ -79,12 +85,14 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public void setMaxFieldSize(int max) throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public int getMaxRows() throws SQLException
{
checkClosed();
@@ -92,18 +100,21 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public void setMaxRows(int max) throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public void setEscapeProcessing(boolean enable) throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public int getQueryTimeout() throws SQLException
{
checkClosed();
@@ -111,18 +122,21 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public void setQueryTimeout(int seconds) throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public void cancel() throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public SQLWarning getWarnings() throws SQLException
{
checkClosed();
@@ -130,18 +144,21 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public void clearWarnings() throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public void setCursorName(String name) throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public boolean execute(String sql) throws SQLException
{
checkClosed();
@@ -149,6 +166,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public ResultSet getResultSet() throws SQLException
{
checkClosed();
@@ -156,6 +174,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public int getUpdateCount() throws SQLException
{
checkClosed();
@@ -163,6 +182,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public boolean getMoreResults() throws SQLException
{
checkClosed();
@@ -170,12 +190,14 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public void setFetchDirection(int direction) throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public int getFetchDirection() throws SQLException
{
checkClosed();
@@ -183,12 +205,14 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public void setFetchSize(int rows) throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public int getFetchSize() throws SQLException
{
checkClosed();
@@ -196,6 +220,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public int getResultSetConcurrency() throws SQLException
{
checkClosed();
@@ -203,6 +228,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public int getResultSetType() throws SQLException
{
checkClosed();
@@ -210,18 +236,21 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public void addBatch(String sql) throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public void clearBatch() throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public int[] executeBatch() throws SQLException
{
checkClosed();
@@ -229,6 +258,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public Connection getConnection() throws SQLException
{
checkClosed();
@@ -236,6 +266,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public boolean getMoreResults(int current) throws SQLException
{
checkClosed();
@@ -243,6 +274,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public ResultSet getGeneratedKeys() throws SQLException
{
checkClosed();
@@ -250,6 +282,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException
{
checkClosed();
@@ -257,6 +290,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException
{
checkClosed();
@@ -264,6 +298,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException
{
checkClosed();
@@ -271,6 +306,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException
{
checkClosed();
@@ -278,6 +314,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException
{
checkClosed();
@@ -285,6 +322,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public boolean execute(String sql, String[] columnNames) throws SQLException
{
checkClosed();
@@ -292,6 +330,7 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public int getResultSetHoldability() throws SQLException
{
checkClosed();
@@ -299,18 +338,21 @@ public class StubStatement implements Statement
}
/** {@inheritDoc} */
+ @Override
public boolean isClosed() throws SQLException
{
return closed;
}
/** {@inheritDoc} */
+ @Override
public void setPoolable(boolean poolable) throws SQLException
{
checkClosed();
}
/** {@inheritDoc} */
+ @Override
public boolean isPoolable() throws SQLException
{
checkClosed();
diff --git a/src/test/resources/propfile1.properties b/src/test/resources/propfile1.properties
index 15f1711a..bf00bdde 100644
--- a/src/test/resources/propfile1.properties
+++ b/src/test/resources/propfile1.properties
@@ -1,4 +1,4 @@
-acquireRetries=5
+minimumIdle=5
connectionTestQuery=SELECT 1
autoCommit=false
dataSourceClassName=com.zaxxer.hikari.mocks.StubDataSource
diff --git a/src/test/resources/propfile3.properties b/src/test/resources/propfile3.properties
new file mode 100644
index 00000000..10fdcf1f
--- /dev/null
+++ b/src/test/resources/propfile3.properties
@@ -0,0 +1,6 @@
+connectionTestQuery=SELECT 1
+autoCommit=false
+dataSourceClassName=com.zaxxer.hikari.mocks.StubDataSource
+dataSource.user=test
+dataSource.password=test
+dataSource.url=jdbc:stub:foo