How testOnBorrow Guarantees Reliable DB Connections in Apache Commons DBCP

This article examines the testOnBorrow mechanism in Apache Commons DBCP, detailing how validation occurs at each layer—from the commons‑pool framework through the DBCP implementation down to the MySQL driver—to ensure robust and high‑availability database connections.

JD Cloud Developers
JD Cloud Developers
JD Cloud Developers
How testOnBorrow Guarantees Reliable DB Connections in Apache Commons DBCP

1. Framework Layer: commons-pool

The testOnBorrow flag, defined by commons‑pool, determines whether an object is validated before being borrowed from the pool. If validation fails, the object is discarded and another is attempted.

/**
 * Borrow an object from the pool. get object from 资源池
 * @see org.apache.commons.pool2.impl.GenericObjectPool#borrowObject(long)
 */
public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
    PooledObject<T> p = null;
    while (p == null) {
        p = idleObjects.pollFirst();
        if (p != null) {
            if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
                boolean validate = false;
                Throwable validationThrowable = null;
                try {
                    // validation implementation provided by the factory
                    // see org.apache.commons.dbcp2.PoolableConnectionFactory
                    validate = factory.validateObject(p);
                } catch (final Throwable t) {
                    PoolUtils.checkRethrow(t);
                    validationThrowable = t;
                }
                if (!validate) {
                    try {
                        // destroy the invalid resource
                        destroy(p);
                        destroyedByBorrowValidationCount.incrementAndGet();
                    } catch (final Exception e) {
                        // ignore – validation failure is more important
                    }
                    p = null;
                }
            }
        }
    }
    return p.getObject();
}

2. Application Layer: commons-dbcp

Commons‑dbcp builds on commons‑pool to manage database connections. It defines PoolableConnectionFactory as a PooledObjectFactory and PoolableConnection as a PooledObject.

/**
 * @see PoolableConnectionFactory#validateObject(PooledObject)
 */
@Override
public boolean validateObject(final PooledObject<PoolableConnection> p) {
    try {
        // check creation time against maxConnLifetimeMillis
        validateLifetime(p);
        // delegate to the actual connection for self‑validation
        validateConnection(p.getObject());
        return true;
    } catch (final Exception e) {
        return false;
    }
}

/**
 * Validate the underlying JDBC connection (closed state, server reachability).
 * @see Connection#isValid(int)
 */
public void validateConnection(final PoolableConnection conn) throws SQLException {
    if (conn.isClosed()) {
        throw new SQLException("validateConnection: connection closed");
    }
    conn.validate(_validationQuery, _validationQueryTimeout);
}

3. Underlying Layer: mysql‑connector‑java

The MySQL driver implements the standard java.sql.Connection.isValid(int) method, sending a ping request to verify that the connection is still usable.

/**
 * Send a ping request via com.mysql.jdbc.MysqlIO to check availability.
 */
public synchronized boolean isValid(int timeout) throws SQLException {
    if (this.isClosed()) {
        return false;
    } else {
        try {
            this.pingInternal(false, timeout * 1000);
            return true;
        } catch (Throwable var5) {
            return false;
        }
    }
}

4. Summary

commons‑pool defines a complete lifecycle interface (makeObject, activateObject, validateObject, passivateObject, destroyObject) that enables precise resource control.

Validation spans multiple time‑related configurations: object creation time, max connection lifetime, JDBC timeout, MySQL idle timeout, each layer contributing to overall reliability.

Connection validation includes checks for closed state at various levels (PoolableConnection, Connection, Socket), providing layered safeguards.

Strict specifications and standards (commons‑pool, JDBC) allow interchangeable implementations and robust integration across components.

5. Understanding High Availability

Examining the MySQL driver source reveals that setting autoReconnect=true triggers a high‑availability path where the driver attempts reconnection up to a configurable limit.

// autoReconnect
public void createNewIO(boolean isForReconnect) throws SQLException {
    synchronized (getConnectionMutex()) {
        // jdbc.url autoReconnect recognized as HighAvailability
        if (!getHighAvailability()) {
            connectOneTryOnly(isForReconnect, mergedProps);
            return;
        }
        // maxReconnects defaults to 3; failure message: "Attempted reconnect 3 times. Giving up."
        connectWithRetries(isForReconnect, mergedProps);
    }
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaConnection PoolDatabase ConnectivityApache Commons DBCP
JD Cloud Developers
Written by

JD Cloud Developers

JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.