Backend Development 7 min read

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.

<code>/**
 * 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();
}
</code>

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

.

<code>/**
 * @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);
}
</code>

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.

<code>/**
 * 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;
        }
    }
}
</code>

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.

<code>// 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);
    }
}
</code>
JavaHigh AvailabilityConnection 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

login 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.