public class DeferredConnectionProxyDataSourceWrapper extends DataSourceWrapper
setAutoCommit(..)
, setTransactionIsolation(..)
, setReadOnly(..)
, and ignores any
commit()
and rollback()
, as well as handling some
surrounding methods like toString(), equals(), hashCode() etc, until the user code e.g. creates a Statement or
PreparedStatement - i.e. not until the user code actually needs to talk to the database. This deferring results in a
situation where if the user code opens a transaction, but does not need to talk to the database after all, and
then commits the transaction, the entire operation is elided - saving several round-trips over the wire.
The use of Java Dynamic Proxies is a simple way to ensure that the implementation is future proof, in that any method
that appears on the Connection in any Java version will be handled by triggering actual Connection fetching and
subsequent call-through to the actual method. Only the methods that are used in standard transaction management are
specially handled to defer the getting of the actual Connection.
Note that it is assumed that the AutoCommit, TransactionIsolation and ReadOnly values are identical for all fetched
Connections (that is, the pool resets them to some default when connection.close()
is
invoked). The default values for these properties are retrieved from the very first Connection that is actually
fetched. The deferring works as such: If you set one of these value on the returned proxied Connection, this will be
recorded, and will subsequently be set on the actual Connection once it is fetched because it is needed (e.g. when a
PreparedStatement is created). However, as a further performance optimization, when about to set the value, it is
compared against those default values gotten from the first Connection, and if they are equal, the actual
setting-invocation is elided.
Inspired by Spring's LazyConnectionDataSourceProxy, but with the additional feature that you can query the Connection
proxy for whether the underlying Connection was actually gotten, since it is a DeferredConnectionProxy
(extends Connection
). It also has the method
actualConnectionWasRetrieved(proxy,
actualConnection)
which can be interesting for extensions. It also has the method
methodInvoked(..)
,
which is invoked after every method invoked on the returned DeferredConnectionProxy
s,
which primarily is interesting for testing, but might have other uses.
If in a Spring environment, the returned Connection instances furthermore implements
org.springframework.jdbc.datasource.ConnectionProxy
.Modifier and Type | Class and Description |
---|---|
static interface |
DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy
Provides a method to query whether the Connection actually was gotten.
|
protected class |
DeferredConnectionProxyDataSourceWrapper.DeferredFetchInvocationHandler
Implementation of Java's "dynamic proxy"
InvocationHandler for deferring fetching of actual Connection
until necessary. |
Modifier and Type | Field and Description |
---|---|
protected java.lang.Boolean |
_autoCommitFromWrappedDataSource |
protected java.lang.Boolean |
_readOnlyFromWrappedDataSource |
protected java.lang.Integer |
_transactionIsolationFromWrappedDataSource |
Modifier | Constructor and Description |
---|---|
protected |
DeferredConnectionProxyDataSourceWrapper() |
protected |
DeferredConnectionProxyDataSourceWrapper(javax.sql.DataSource targetDataSource) |
Modifier and Type | Method and Description |
---|---|
protected void |
actualConnectionWasRetrieved(DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy connectionProxy,
java.sql.Connection actualConnection)
Override if you want to know when the actual Connection was retrieved.
|
java.lang.Boolean |
getAutoCommitFromWrappedDataSource() |
DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy |
getConnection() |
DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy |
getConnection(java.lang.String username,
java.lang.String password) |
java.lang.Boolean |
getReadOnlyFromWrappedDataSource() |
java.lang.Integer |
getTransactionIsolationFromWrappedDataSource() |
protected void |
methodInvoked(boolean answeredByProxy,
DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy connectionProxy,
java.sql.Connection actualConnection,
java.lang.reflect.Method method,
java.lang.Object[] args,
java.lang.Object result)
Override if you want to know about every method invoked on the
DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy , its arguments
and its return value, and whether it was the proxy or the actual Connection that answered. |
protected void |
retrieveDefaultAutoCommitAndTransactionIsolationAndReadOnlyValues(java.sql.Connection con) |
static DeferredConnectionProxyDataSourceWrapper |
wrap(javax.sql.DataSource dataSource) |
getLoginTimeout, getLogWriter, getParentLogger, isWrapperFor, setLoginTimeout, setLogWriter, setWrappee, toString, unwrap, unwrap
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
unwrapFully, unwrapTo
protected volatile java.lang.Boolean _autoCommitFromWrappedDataSource
protected volatile java.lang.Integer _transactionIsolationFromWrappedDataSource
protected volatile java.lang.Boolean _readOnlyFromWrappedDataSource
protected DeferredConnectionProxyDataSourceWrapper()
protected DeferredConnectionProxyDataSourceWrapper(javax.sql.DataSource targetDataSource)
public static DeferredConnectionProxyDataSourceWrapper wrap(javax.sql.DataSource dataSource)
dataSource
- the DataSource to wrap.public DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy getConnection() throws java.sql.SQLException
getConnection
in interface javax.sql.DataSource
getConnection
in class DataSourceWrapper
java.sql.SQLException
- can actually never throw SQLException, since it just gives you a proxy.public DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy getConnection(java.lang.String username, java.lang.String password) throws java.sql.SQLException
getConnection
in interface javax.sql.DataSource
getConnection
in class DataSourceWrapper
username
- username to to forward to underlying DataSource.getConnection(username, password) when Connection
needs to be gotten.password
- password to to forward to underlying DataSource.getConnection(username, password) when Connection
needs to be gotten.java.sql.SQLException
- can actually never throw SQLException, since it just gives you a proxy.protected void actualConnectionWasRetrieved(DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy connectionProxy, java.sql.Connection actualConnection)
protected void methodInvoked(boolean answeredByProxy, DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy connectionProxy, java.sql.Connection actualConnection, java.lang.reflect.Method method, java.lang.Object[] args, java.lang.Object result)
DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy
, its arguments
and its return value, and whether it was the proxy or the actual Connection that answered. Default implementation
does nothing.public java.lang.Boolean getAutoCommitFromWrappedDataSource()
null
until the first underlying Connection has actually been gotten, after that what this
first underlying Connection replied to invocation of Connection.getAutoCommit()
.public java.lang.Integer getTransactionIsolationFromWrappedDataSource()
null
until the first underlying Connection has actually been gotten, after that what this
first underlying Connection replied to invocation of Connection.getTransactionIsolation()
.public java.lang.Boolean getReadOnlyFromWrappedDataSource()
null
until the first underlying Connection has actually been gotten, after that what this
first underlying Connection replied to invocation of Connection.isReadOnly()
.protected void retrieveDefaultAutoCommitAndTransactionIsolationAndReadOnlyValues(java.sql.Connection con) throws java.sql.SQLException
java.sql.SQLException