Data source instantiation was introduced during the MybatisPlus startup phase. At that time, there was no actual connection to the database. In this article, we will use druid connection pool as an example to introduce database connection pool.
Similar to the concept of the thread pool, database connection pool is the management of database connection, we know that Web application and the database connection is very frequent, if each connection closed again, this is a waste of resources and performance, the emergence of database connection pool, make connection with the database can be directly obtained from the pool, run out again to the connection pool, Connection pooling also manages resources, such as resource creation, recycling, closing, and so on.
The connection
// The dataSource is DruidDataSourceWrapper class. DruidDataSource->getConnection(): return getConnection(maxWait); DruidDataSourceWrapper -> DruidDataSource->getConnection(): // Call DruidDataSourceWrapper once; // Using the chain of responsibility pattern, finally call the getConnectionDirect() method...... DruidDataSource->getConnectionDirect(): poolableConnection = getConnectionInternal(maxWaitMillis); DruidDataSource->getConnectionInternal(): // maxWait defaults to -1, else if (maxWait > 0) {holder = pollLast(nanos); } else { holder = takeLast(); } DruidDataSource->takeLast(): // poolingCount == 0; / / - 1... notEmpty.await(); / / - 2Copy the code
The first time you get a connection to a database, you have to go to –1.
DruidDataSource->emptySignal():
if (createScheduler == null) {
empty.signal();
return;
}
Copy the code
Empty.await () is called by the thread that created the connection when the data source is instantiated in the startup phase, where empty.signal() is called to wake it up. The main thread returns, blocked at –2.
DruidDataSource->CreateConnectionThread->run(): for (;;) {... If (activeCount + poolingCount >= maxActive) {(activeCount + poolingCount >= maxActive) { empty.await(); // --3 continue; Connection = createPhysicalConnection(); connection = createPhysicalConnection(); connection = createPhysicalConnection(); . Boolean result = put(connection); } DruidDataSource->put(): // return put(holder); DruidDataSource->put(): if (poolingCount >= maxActive) { return false; } connections[poolingCount] = holder; PoolingCount = 1 incrementPoolingCount(); . notEmpty.signal(); / / - 4Copy the code
Call notempty.signal () to wake up — block at 2, at which point poolingCount is no longer 0 and the loop is broken.
DruidDataSource->takeLast(): decrementPoolingCount(); // Get a connection from the connections array and return DruidConnectionHolder last = connections[poolingCount]; connections[poolingCount] = null; return last;Copy the code
As you can see from the code, getting a connection from a connection pool is actually taking a value from the Connections array and subscripting it to NULL. There are many different ways to get a connection, but this is just the simplest one.
recycling
When you’re done with connections, call Connection.close () to close the connection, where connection is the DruidPooledConnection object, and its closing method will eventually call dataSource.recycle().
DruidDataSource->recycle(): ...... // Restore the data source property to the default holder.reset(); . result = putLast(holder, lastActiveTimeMillis); DruidDataSource->putLast(): DruidDataSource->putLast(): DruidDataSource->putLast(): incrementPoolingCount(); . notEmpty.signal(); / / - 5Copy the code
In the case of thread pools, this is done by simply assigning a physical connection to the connections subscript, and then waking it up at some point if a thread is blocked at two points.
The configuration properties
Yml configuration: datasource: # datasource attribute...... druid: min-idle: 1 max-active: 2 max-wait: 10 validation-query: SELECT 1 time-between-eviction-runs-millis: 5 min-evictable-idle-time-millis: 5 max-evictable-idle-time-millis: 50Copy the code
After the first connection and collection, the poolingCount is no longer 0 and can be retrieved from the Connections array.
Maximum number of connections
Connections are acquired synchronously in the same thread. If they are acquired simultaneously in different threads, the thread pool creates multiple physical connections for use, but this number is not infinite. If max-active is not set, the default is 8.
If the maximum number of connections is already full, the thread that created the connection blocks at –3 and the main thread blocks at –2. Call notempty.signal () at –5 to wake up the block at –2 until a thread pool has reclaimed connections from other threads. If there are multiple threads, the first one to block will be woken up. Again through the loop, poolingCount is no longer 0, and the value is returned from the connections array.
Maximum waiting time
If max-wait is set, the holder = pollLast(nanOS) method is called.
DruidDataSource->pollLast():
estimate = notEmpty.awaitNanos(estimate);
Copy the code
Notempty.await () is called to wait indefinitely. Notempty.awaitnanos (estimate) is called to wait indefinitely. If the estimate returns less than 0, it has timed out. Anything less than 0 will throw an exception corresponding to a timeout.
Close connection, detection time and idle time
CreateConnectionThread creates database connections, and DestroyConnectionThread closes database connections.
DruidDataSource->DestroyConnectionThread->run(): for (;;) {/ / timeBetweenEvictionRunsMillis namely detection time here, If the default is 60 s (timeBetweenEvictionRunsMillis > 0) {thread.sleep (timeBetweenEvictionRunsMillis); } else { Thread.sleep(1000); } // Synchronously execute the thread method destroyTask.run() to close the database connection; } DruidDataSource->DestroyTask->run(): shrink(true, keepAlive); DruidDataSource->shrink(): // Final int checkCount = poolingCount - minIdle; Final Long currentTimeMillis = System.currentTimemillis (); for (int i = 0; i < poolingCount; DruidConnectionHolder Connection = connections[I]; DruidConnectionHolder connection = connections[I]; . / / leisure time = current time minus the last active time long idleMillis = currentTimeMillis - connection. LastActiveTimeMillis; / / the minEvictableIdleTimeMillis namely the minimum free time here if (idleMillis < minEvictableIdleTimeMillis) {/ / if the free time is less than the last active time, directly out of the loop, This is because as connections subscript increases, the active time also increases by a break; If (checkTime && I < checkCount) {evictConnections[evictCount++] = connection; // If the free time is greater than the set maximum free time, Say what also want to close the connection} else if (idleMillis > maxEvictableIdleTimeMillis) {evictConnections [evictCount++] = connection; } else if (keepAlive) { keepAliveConnections[keepAliveCount++] = connection; Int removeCount = evictCount + keepAliveCount; If (removeCount > 0) {if (removeCount > 0) {if (removeCount > 0) {if (removeCount > 0) { poolingCount - removeCount); Arrays.fill(connections, poolingCount - removeCount, poolingCount, null); poolingCount -= removeCount; If (evictCount > 0) {for (int I = 0; i < evictCount; DruidConnectionHolder item = evictConnections[I]; DruidConnectionHolder item = evictConnections[I]; Connection connection = item.getConnection(); JdbcUtils.close(connection); destroyCount.incrementAndGet(); } Arrays.fill(evictConnections, null); }...Copy the code
conclusion
- The DruidDataSource member variable connections is the core of the DruidDataSource connection pool. The DruidDataSource member variable connections is the core of the DruidDataSource connection pool
- ConditionObject (ConditionObject); ConditionObject (ConditionObject); ConditionObject (ConditionObject)