Database connection pool implementation details

Keywords: Java JDBC SQL Database

First, a PooledConnection class is created to encapsulate the connection information;

package com.bai.pool;

import java.sql.Connection;

/**
 * 
* Copyright: Copyright (c) 2018 LanRu-Caifu
* 
* @ClassName: PooledConnection.java
* @Description: Connection information stored in connection pool
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018 11:48:10 am, July 29, 2010
 */
public class PooledConnection {
	//Database connection
	private  Connection connection;
	//Connection state
	private boolean isUsed;
	
	public PooledConnection(Connection connection,boolean isUsed) {
		this.connection = connection;
		this.isUsed = isUsed;
	}
	
	public Connection getConnection() {
		return connection;
	}
	//get,set method
	public void setConnection(Connection connection) {
		this.connection = connection;
	}
	
	public boolean isUsed() {
		return isUsed;
	}
	
	public void setUsed(boolean isUsed) {
		this.isUsed = isUsed;
	}

	/**   
	* @Function: PooledConnection.java
	* @Description: Discard use of connection
	*
	* @param:Description 1 Description
	* @return: Return result description
	* @throws: Exception description
	*
	* @version: v1.0.0
	* @author: Mr white
	* @date: 2018 7:02:31 PM, July 29, 2010 
	*/
	public void close() {
		System.out.println("Return connection use right");
		this.isUsed = false;
	}
}

Create the abstract class AbstractDataSourcePool specification of the connection pool external getConnection():

package com.bai.pool;
/**
 * 
* Copyright: Copyright (c) 2018 LanRu-Caifu
* 
* @ClassName: AbstractDataSourcePool.java
* @Description: Connection pool abstract class
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018 11:49:14 am, July 29, 2010
 */
public abstract class AbstractDataSourcePool {
	/**
	 * 
	* @Function: AbstractDataSourcePool.java
	* @Description: How to get a connection
	*
	* @param:Description 1 Description
	* @return: Return result description
	* @throws: Exception description
	*
	* @version: v1.0.0
	* @author: Mr white
	* @date: 2018 11:49:33 am, July 29, 2010
	 */
	public abstract PooledConnection getConnection();
}

To implement the profile loader PropertiesPlaceHolder:

/**   
 * Copyright © 2018 eSunny Info. Tech Ltd. All rights reserved.
 * 
 *  Function Description:
 * @Package: com.bai.pool.prop 
 * @author: Mr white   
 * @date: 2018 11:59:47 am, July 29, 2010 
 */
package com.bai.pool.prop;

import java.io.InputStream;
import java.util.Properties;

/**   
* Copyright: Copyright (c) 2018 LanRu-Caifu
* 
* @ClassName: PropertiesPlaceHolder.java
* @Description: Tool class to read properties
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018 11:59:47 am, July 29, 2010 
*/
public class PropertiesPlaceHolder extends Properties {

	private static final long serialVersionUID = 1L;
		
	public PropertiesPlaceHolder(String properties) {
		try {
			InputStream in = this.getClass().getClassLoader().getResourceAsStream(properties);
			//load configuration
			this.load(in);
		} catch (Exception e) {
			e.printStackTrace();
		}
	} 
}

Configuration file jdbc.properties:

jdbc.driver.class = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://127.0.0.1:3306/ssm_ee?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true
jdbc.username = root
jdbc.password = root

initSize = 3
maxSize = 20
incrSize = 5
timeOut = 1000

Write the core connection pool class DataSourcePool to inherit AbstractDataSourcePool:

/**   
 * Copyright © 2018 eSunny Info. Tech Ltd. All rights reserved.
 * 
 *  Function Description:
 * @Package: com.bai.pool 
 * @author: Mr white   
 * @date: 2018 11:50:15 am, July 29, 2015 
 */
package com.bai.pool;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.TimeUnit;

import com.bai.pool.prop.PropertiesPlaceHolder;

/**   
* Copyright: Copyright (c) 2018 LanRu-Caifu
* 
* @ClassName: DataSourcePool.java
* @Description: Function description of this class
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018 11:50:15 am, July 29, 2015 
*/
public class DataSourcePool extends AbstractDataSourcePool {
	//Database driver name
	private String driverClassName;
	//Database connection address
	private String url;
	//Database user name
	private String username;
	//Database password
	private String password;
	//Number of initial connections
	private int initSize = 3;
	//Maximum number of connections
	private int maxSize = 20;
	//When the current connection in the connection pool has not reached the maximum number of connections after use, the number of connections initialized
	private int incrSize = 5;
	//Timeout time
	private int timeOut = 1000;
	//Polling interval milliseconds
	private int timeSpace = 30;
	
	//Cable object
	Object lockObj = new Object();
	//Thread safe collection of connections
	public Vector<PooledConnection> connectionPool = new Vector<PooledConnection>();
	
	public DataSourcePool() {
		initPool();
	}
	/**   
	* @Function: DataSourcePool.java
	* @Description: Function description of this function
	*
	* @param:Description 1 Description
	* @return: Return result description
	* @throws: Exception description
	*
	* @version: v1.0.0
	* @author: Mr white
	* @date: 2018 11:55:27 a.m., July 29, 2010 
	*/
	private void initPool() {
		//Initialize the object to read the file
		Properties prop = new PropertiesPlaceHolder("jdbc.properties");
		//Read profile information
		driverClassName = prop.getProperty("jdbc.driver.class");
		url = prop.getProperty("jdbc.url");
		username = prop.getProperty("jdbc.username");
		password = prop.getProperty("jdbc.password");
		//Dynamically configure connection pool information
		String initSizeStr = prop.getProperty("initSize");
		String maxSizeStr = prop.getProperty("maxSize");
		String incrSizeStr = prop.getProperty("incrSize");
		String timeOutStr = prop.getProperty("timeOut");
		String timeSpaceStr = prop.getProperty("timeSpace");
		initSize = initSizeStr == null ? initSize : Integer.parseInt(initSizeStr);
		maxSize = maxSizeStr == null ? maxSize : Integer.parseInt(maxSizeStr);
		incrSize = incrSizeStr == null ? incrSize : Integer.parseInt(incrSizeStr);
		timeOut = timeOutStr == null ? timeOut : Integer.parseInt(timeOutStr);
		timeSpace = timeSpaceStr == null ? timeSpace : Integer.parseInt(timeSpaceStr);
		
		try {//Register the corresponding driver in DriverManager
			Driver driver = (Driver) Class.forName(driverClassName).newInstance();
			DriverManager.registerDriver(driver);
		} catch (Exception e) {
			
		}
	}
	/** 
	* @see com.bai.pool.AbstractDataSourcePool#getConnection()  
	* @Function: DataSourcePool.java
	* @Description: Function description of this function
	*
	* @param:Description 1 Description
	* @return: Return result description
	* @throws: Exception description
	*
	* @version: v1.0.0
	* @author: Mr white
	* @date: 2018 11:50:15 am, July 29, 2015 
	*/
	@Override
	public PooledConnection getConnection() {
		PooledConnection connection = null;
		synchronized(lockObj) {
			//Connection pool is not linked
			if(connectionPool.size()==0) {
				System.out.println("Initialize connections in the connection pool using the connection pool for the first time");
				createConnections(initSize);
			}
			connection = getRealConnection();
			//If you do not get to the connection poll get objects in the connection pool
			if(connection == null) {
				while(connection == null) {
					//Continue to create connection
					createConnections(incrSize);
					connection = getRealConnection();
					try {
						TimeUnit.MILLISECONDS.sleep(timeSpace);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}
		return connection;
	}
	/**   
	* @Function: DataSourcePool.java
	* @Description: Filter out available database connections
 	* @return: Return result description
	* @throws: Exception description
	*
	* @version: v1.0.0
	* @author: Mr white
	* @date: 2018 5:13:26 PM, July 29, 2010 
	*/
	private PooledConnection getRealConnection() {
		//Traverse connection to determine whether it is available
		for(int i = 0; i < connectionPool.size(); i++) {
			PooledConnection conn = connectionPool.get(i);
			if(!conn.isUsed()) {
				//Get java.sql.connection object
				Connection connection = conn.getConnection();
				try {
					if(!connection.isValid(timeOut)) {
						connection = DriverManager.getConnection(url, username, password);
						//Make up damaged connections
						conn.setConnection(connection);
					}
					conn.setUsed(true);
					System.out.println("Get to connection object"+conn);
					return conn;
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} 
		return null;
	}
	/**   
	* @Function: DataSourcePool.java
	* @Description: Add connection object to connection pool
	*
	* @param:Description 1 Description
	* @return: Return result description
	* @throws: Exception description
	*
	* @version: v1.0.0
	* @author: Mr white
	* @date: 2018 5:05:26 PM, July 29, 2010 
	*/
	private void createConnections(int initCount) {
		//Determine the number of connections in the pool < = maximum number of connections
		if(connectionPool.size() + incrSize > maxSize) {
			initCount = maxSize - connectionPool.size();
		}
		//Ship connection object
		for(int i = 0;i<initCount; i++) {
			try {
				Connection connection = DriverManager.getConnection(url, username, password);
				//Load connections into objects
				PooledConnection conn = new PooledConnection(connection, false);
				connectionPool.add(conn);
				System.out.printf("Create the first%d A connection\n",connectionPool.size());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

}

Add corresponding dependency and write test class:

/**   
 * Copyright © 2018 eSunny Info. Tech Ltd. All rights reserved.
 * 
 *  Function Description:
 * @Package: com.bai.pool 
 * @author: Mr white   
 * @date: 2018 6:55:37 PM, July 29, 2007 
 */
package com.bai.pool;

import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**   
* Copyright: Copyright (c) 2018 LanRu-Caifu
* 
* @ClassName: Test.java
* @Description: Function description of this class
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018 6:55:37 PM, July 29, 2007 
*/
public class Test {
	static DataSourcePool pool =  new DataSourcePool();
	public static void testConnection() {
		PooledConnection connection = pool.getConnection();
		PreparedStatement prep = null;
		ResultSet rs = null;
		try {
			prep = connection.getConnection().prepareStatement("select * from sys_user");
			rs = prep.executeQuery();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(rs != null) {
					rs.close();
				}
				if(prep != null) {
					prep.close();
				}
				if(connection != null) {
					connection.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		for(int i=0;i<10000;i++)
			testConnection();
		/*new Thread(new Runnable() {
			@Override
			public void run() {
				testConnection();
			}
		}).start();*/
	}
}

Implement single and multi-threaded testing:

As a result, a single thread always starts a single thread; the more access threads in multithreading, the more connections are occupied

Posted by ashmo on Sun, 26 Jan 2020 10:24:24 -0800