Package io.mats3.util.wrappers
Class DeferredConnectionProxyDataSourceWrapper
java.lang.Object
io.mats3.util.wrappers.DataSourceWrapper
io.mats3.util.wrappers.DeferredConnectionProxyDataSourceWrapper
- All Implemented Interfaces:
MatsFactory.MatsWrapper<DataSource>
,Wrapper
,CommonDataSource
,DataSource
- Direct Known Subclasses:
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx.DeferredConnectionProxyDataSourceWrapper_InfrastructureProxy
DataSource wrapper which returns thin Connection proxies (currently employing Java's "dynamic proxy" functionality)
which do not actually fetch a Connection until it is needed. It defers as long as possible, "holding back" calls to
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
.-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interface
Provides a method to query whether the Connection actually was gotten.protected class
Implementation of Java's "dynamic proxy"InvocationHandler
for deferring fetching of actual Connection until necessary. -
Field Summary
Fields -
Constructor Summary
ConstructorsModifierConstructorDescriptionprotected
protected
DeferredConnectionProxyDataSourceWrapper
(DataSource targetDataSource) -
Method Summary
Modifier and TypeMethodDescriptionprotected void
actualConnectionWasRetrieved
(DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy connectionProxy, Connection actualConnection) Override if you want to know when the actual Connection was retrieved.getConnection
(String username, String password) protected void
methodInvoked
(boolean answeredByProxy, DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy connectionProxy, Connection actualConnection, Method method, Object[] args, Object result) Override if you want to know about every method invoked on theDeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy
, its arguments and its return value, and whether it was the proxy or the actual Connection that answered.protected void
wrap
(DataSource dataSource) Methods inherited from class io.mats3.util.wrappers.DataSourceWrapper
getLoginTimeout, getLogWriter, getParentLogger, isWrapperFor, setLoginTimeout, setLogWriter, setWrappee, toString, unwrap, unwrap
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
Methods inherited from interface javax.sql.CommonDataSource
createShardingKeyBuilder
Methods inherited from interface javax.sql.DataSource
createConnectionBuilder
Methods inherited from interface io.mats3.MatsFactory.MatsWrapper
unwrapFully, unwrapTo
-
Field Details
-
_autoCommitFromWrappedDataSource
-
_transactionIsolationFromWrappedDataSource
-
_readOnlyFromWrappedDataSource
-
-
Constructor Details
-
DeferredConnectionProxyDataSourceWrapper
protected DeferredConnectionProxyDataSourceWrapper() -
DeferredConnectionProxyDataSourceWrapper
-
-
Method Details
-
wrap
- Parameters:
dataSource
- the DataSource to wrap.- Returns:
- an instance of this class wrapping the supplied DataSource.
-
getConnection
public DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy getConnection() throws SQLException- Specified by:
getConnection
in interfaceDataSource
- Overrides:
getConnection
in classDataSourceWrapper
- Returns:
- a "thin Proxy", implemented as Java's "dynamic proxy", NOT YET proxying an actual Connection.
- Throws:
SQLException
- can actually never throw SQLException, since it just gives you a proxy.
-
getConnection
public DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy getConnection(String username, String password) throws SQLException - Specified by:
getConnection
in interfaceDataSource
- Overrides:
getConnection
in classDataSourceWrapper
- Parameters:
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.- Returns:
- a "thin Proxy", implemented as Java's "dynamic proxy", NOT YET proxying an actual Connection.
- Throws:
SQLException
- can actually never throw SQLException, since it just gives you a proxy.
-
actualConnectionWasRetrieved
protected void actualConnectionWasRetrieved(DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy connectionProxy, Connection actualConnection) Override if you want to know when the actual Connection was retrieved. Default implementation logs to debug. -
methodInvoked
protected void methodInvoked(boolean answeredByProxy, DeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy connectionProxy, Connection actualConnection, Method method, Object[] args, Object result) Override if you want to know about every method invoked on theDeferredConnectionProxyDataSourceWrapper.DeferredConnectionProxy
, its arguments and its return value, and whether it was the proxy or the actual Connection that answered. Default implementation does nothing. -
getAutoCommitFromWrappedDataSource
- Returns:
null
until the first underlying Connection has actually been gotten, after that what this first underlying Connection replied to invocation ofConnection.getAutoCommit()
.
-
getTransactionIsolationFromWrappedDataSource
- Returns:
null
until the first underlying Connection has actually been gotten, after that what this first underlying Connection replied to invocation ofConnection.getTransactionIsolation()
.
-
getReadOnlyFromWrappedDataSource
- Returns:
null
until the first underlying Connection has actually been gotten, after that what this first underlying Connection replied to invocation ofConnection.isReadOnly()
.
-
retrieveDefaultAutoCommitAndTransactionIsolationAndReadOnlyValues
protected void retrieveDefaultAutoCommitAndTransactionIsolationAndReadOnlyValues(Connection con) throws SQLException - Throws:
SQLException
-