Class ConnectionState

java.lang.Object
org.apache.tomcat.jdbc.pool.JdbcInterceptor
org.apache.tomcat.jdbc.pool.interceptor.ConnectionState
All Implemented Interfaces:
InvocationHandler

public class ConnectionState extends JdbcInterceptor
Interceptor that keeps track of connection state to avoid roundtrips to the database. The ConnectionPool is optimized to do as little work as possible. The pool itself doesn't remember settings like Connection.setAutoCommit(boolean), Connection.setReadOnly(boolean), Connection.setCatalog(String) or Connection.setTransactionIsolation(int). It relies on the application to remember how and when these settings have been applied. In the cases where the application code doesn't know or want to keep track of the state, this interceptor helps cache the state, and it also avoids roundtrips to the database asking for it.

Caching is only half the role. Once this interceptor is configured, the pool hands it the enforcement of the four configured defaults - defaultAutoCommit, defaultReadOnly, defaultTransactionIsolation and defaultCatalog: PooledConnection.connect() no longer applies them at connection creation, and reset(ConnectionPool, PooledConnection) applies them to every borrow and re-applies whatever a previous borrower changed, on the terms that method states.

A subclass that overrides reset(ConnectionPool, PooledConnection) must call the superclass, or apply those defaults itself. The pool recognises this class by type and, having found it, leaves the defaults to the interceptor alone; an override that skips the superclass therefore silently drops both the connect-time application and the borrow-time restore, warning no one.

  • Field Details

    • readState

      protected final String[] readState
      Method names for reading connection state. The index into this array and into writeState is the identity of a tracked state across the class: 0 is the auto-commit state, 1 the transaction isolation level, 2 the read only state and 3 the catalog. The entry at an index of writeState is the setter whose value the cache field of the same index holds, and invoke(Object, Method, Object[]) matches both arrays by index against the cache fields. Reordering one array without the other would map a setter's value into the wrong field; adding a tracked state means all three - both arrays, the cache field, and the matching in invoke(Object, Method, Object[]) - at once.
    • writeState

      protected final String[] writeState
      Method names for writing connection state, indexed as readState.
    • autoCommit

      protected Boolean autoCommit
      Cached auto-commit state of the connection.
    • transactionIsolation

      protected Integer transactionIsolation
      Cached transaction isolation level of the connection.
    • readOnly

      protected Boolean readOnly
      Cached read-only state of the connection.
    • catalog

      protected String catalog
      Cached catalog (database) name of the connection.
  • Constructor Details

    • ConnectionState

      public ConnectionState()
      Creates a new ConnectionState interceptor instance.
  • Method Details

    • reset

      public void reset(ConnectionPool parent, PooledConnection con)
      Restores the connection state the pool was configured to enforce. The pool invokes this on every borrow, before the connection is handed to its next borrower.

      When any restore is pending, a transaction the previous borrower left open is terminated first: isolation and read only are transaction scoped on many drivers, an open transaction would absorb the restores, and restoring auto-commit would silently commit the previous borrower's work. Failing to terminate that transaction, and a confirmed refusal to restore the read-only, auto-commit or catalog state, fail the borrow and retire the session - a connection known to sit in a state other than the configured one must not reach a borrower. A refusal the driver blames on the session's transaction state is confirmed first, against a session freed of it (confirmAgainstFreedSession(PooledConnection, SQLException, ConnectionState.RestoreAttempt)).

      A transaction isolation level the driver refuses on a freed session is the one confirmed failure that does not retire the connection: the level is recorded (refusedIsolationLevel) and stops counting as a pending restore, so later borrows neither retry it nor pay a transaction termination on its behalf. When nothing needs restoring, nothing is terminated - a pool that uses this interceptor only to cache the state pays nothing.

      Specified by:
      reset in class JdbcInterceptor
      Parameters:
      parent - the pool the connection belongs to, or null when the interceptor chain is being torn down
      con - the pooled connection being set up for its next borrower
    • disconnected

      public void disconnected(ConnectionPool parent, PooledConnection con, boolean finalizing)
      Description copied from class: JdbcInterceptor
      Called when Connection.close() is called on the underlying connection. This is to notify the interceptors, that the physical connection has been released. Implementation of this method should be thought through with care, as no actions should trigger an exception. An interceptor that nevertheless throws is isolated: the exception is logged and ignored, the remaining interceptors in the chain are still notified, and the physical connection is closed as it would have been. As for JdbcInterceptor.reset(ConnectionPool, PooledConnection), a hook must not rewire the chain from this callback: chain topology is owned by the pool.
      Overrides:
      disconnected in class JdbcInterceptor
      Parameters:
      parent - - the connection pool that this connection belongs to
      con - - the pooled connection that holds this connection
      finalizing - - if this connection is finalizing. True means that the pooled connection will not reconnect the underlying connection
    • invoke

      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
      Description copied from class: JdbcInterceptor
      Gets invoked each time an operation on Connection is invoked.

      The base implementation passes the call to the next interceptor in the chain. When there is no next interceptor, the call fails fast with a NullPointerException: a chain built by the pool always ends in the ProxyConnection terminal, so reaching this case means a chain was hand-built without a terminal link. Interceptors that do not answer a call themselves continue it with super.invoke(proxy, method, args).

      Specified by:
      invoke in interface InvocationHandler
      Overrides:
      invoke in class JdbcInterceptor
      Throws:
      Throwable