Databases 23 min read

In‑Depth Analysis of Druid Connection‑Pool Lifecycle and Internal Processes

This article provides a comprehensive walkthrough of Druid's connection‑pool architecture, detailing the initialization, acquisition, validation, eviction, and recycling of connections, while explaining key configuration options, thread‑safety mechanisms, and performance considerations for Java database applications.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
In‑Depth Analysis of Druid Connection‑Pool Lifecycle and Internal Processes

Overview

The article examines Druid's connection‑pool implementation, using getConnection as the entry point to explore the full lifecycle of a connection, and divides the overall workflow into several major processes.

Main Process 1: Acquiring a Connection

When a connection is requested, Druid first calls init to ensure the pool is initialized, then executes each filter in the responsibility chain before finally invoking getConnectionDirect . If testOnBorrow is enabled, the connection is validated on every borrow, which can degrade performance because MySQL long‑connection keep‑alive defaults to 8 hours.

If testOnBorrow is disabled, Druid relies on testWhileIdle , which checks idle connections at intervals defined by timeBetweenEvictionRunsMillis (default 60 s). The pool records the last usage time of each connection and compares idle time against this interval to decide whether to run a validation.

When a validation fails via testConnectionInternal , the connection is discarded through discardConnection , triggering the creation of a new connection if needed. The retry logic limits attempts using notFullTimeoutRetryCount and caps waiting time with 2 × maxWait .

Special Note ①

For best performance, keep testOnBorrow disabled and rely on the default idle‑check interval (60 s). Adjust timeBetweenEvictionRunsMillis only if the MySQL server’s long‑connection timeout is shorter than 60 s.

Special Note ②

In high‑QPS services, set minIdle equal to maxActive and enable keepAlive to avoid dynamic expansion; for low‑traffic admin tools, a smaller minIdle can reduce unnecessary connections.

Main Process 2: Initializing the Pool

If the pool is not yet initialized (checked via the inited flag), Druid calls init . This method creates a global re‑entrant lock, performs double‑checked locking, loads filters via SPI, and allocates three arrays ( connections , evictConnections , keepAliveConnections ) sized to maxActive . It then creates initialSize connections and starts two daemon threads for adding and evicting connections.

Special Note ①

Delaying pool initialization until the first getConnection call can cause a long pause on the first request, especially under high concurrency; pre‑warming the pool by invoking init early is recommended.

Special Note ②

The lock creates two Condition objects: empty (used by the add‑connection daemon) and notEmpty (used by threads waiting for a connection). When the pool is exhausted, business threads block on notEmpty while the daemon thread is signaled via empty to create new connections.

Process 1.1: Responsibility Chain

Each DruidAbstractDataSource holds a list of filters . When getConnection is invoked, the FilterChain sequentially calls the corresponding method on each filter (e.g., dataSource_getConnection ) until the chain ends and getConnectionDirect is executed.

Process 1.2: Getting a Connection from the Pool

If a connection is available, the pool decrements poolingCount , returns the connection, and increments activeCount (O(1) operation). When no connection is available, Druid wakes the add‑connection daemon, then the requesting thread waits on notEmpty with a timeout governed by maxWait . The wait time is reduced on each retry using awaitNanos . If the timeout expires, null is returned and the retry logic in Process 1 is triggered.

How to Limit Blocking Threads

Setting maxWaitThreadCount (> 0) caps the number of threads that may block waiting for a connection. When the count exceeds the limit, Druid throws an SQLException instead of entering the wait state.

Process 1.3: Connection Validation

Druid creates a checker during initialization. For MySQL, if the driver provides a ping method, the checker uses it; otherwise it falls back to executing SELECT 1 . The testConnectionInternal method invokes the checker’s isValidConnection to determine connection health.

Process 1.4: Discarding a Connection

If validation fails, the connection’s activeCount is decremented and the underlying JDBC Connection is closed. If the connection is a DruidPooledConnection , calling close triggers the recycle logic instead of immediate disposal.

Main Process 3: Add‑Connection Daemon Thread

This daemon thread remains idle until signaled via empty when the pool needs more connections. After creating a connection, it signals notEmpty to wake waiting business threads, implementing a producer‑consumer model.

Main Process 4: Eviction Daemon Thread

The eviction thread periodically examines idle connections. It calculates a check range using poolingCount - minIdle and applies two thresholds:

minEvictableIdleTimeMillis (default 30 min): connections idle longer than this within the check range become candidates for eviction.

maxEvictableIdleTimeMillis (default 7 h): any connection idle beyond this is evicted unconditionally.

Connections that are not evicted but have been idle longer than keepAliveBetweenTimeMillis (default 60 s) are placed in keepAliveConnections for a lightweight validation check.

Process 4.2: Active‑Connection Leak Prevention

When removeAbandoned=true , the daemon scans activeConnections for connections that have been borrowed for too long, moves them to abandonedList , and forces their closure to avoid memory leaks.

Main Process 5: Recycling a Connection

The recycle step is triggered by the close method of DruidPooledConnection . It may rollback any uncommitted transaction, reset the connection state, optionally run testOnReturn , and finally place the connection at the tail of the connections list, updating lastActiveTimeMillis .

Conclusion

The article has mapped out the complete lifecycle of a Druid connection—from pool initialization, through acquisition, validation, eviction, and recycling—highlighting the key configuration parameters that affect performance and reliability.

JavaperformanceDatabaseConnection PoolThread SafetyDruid
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

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.