Java中的连接池

时间:2020-02-23 14:36:11  来源:igfitidea点击:

连接池是指连接对象池。
连接池基于对象池设计模式。
当创建新对象的成本(时间和资源,如CPU,网络和IO)较高时,将使用对象池设计模式。
按照对象池设计模式,应用程序会预先创建一个对象并将其放置在"池"或者"容器"中。
每当我们的应用程序需要此类对象时,它都会从池中获取它们,而不是创建一个新的对象。

使用连接池策略的应用程序已经具有可重复使用的数据库连接对象。
因此,当需要与数据库进行交互时,应用程序将从Pool中获取连接实例。
连接池提高了与数据库交互的应用程序性能。

我们可以创建自己的连接池实现。
任何连接池框架都需要完成三个任务。

  • 创建连接对象
  • 管理创建的对象的使用并验证它们
  • 释放/销毁对象

使用Java,我们有大量可用的库。
我们只需要配置一些属性即可使用它们。

Java应用程序中的连接池

让我们看一下下面的库:

  • Apache Commons DBCP 2
  • 光明CP
  • C3P0

让我们逐一查看以下示例。
出于演示目的,我们将使用MySQL数据库和Eclipse IDE。
我们还将使用JDK 1.8基于maven创建简单的Java项目。

数据库脚本

create database empdb;

use empdb;

create table tblemployee(
                  empId integer AUTO_INCREMENT primary key,
                  empName varchar(64),
                  dob date,
                  designation varchar(64)
);

insert into  tblemployee(empId,empName,dob,designation) values (default,'Adam','1998-08-15','Manager');
insert into  tblemployee(empId,empName,dob,designation) values (default,'Smith','2001-01-11','Clerk');
insert into  tblemployee(empId,empName,dob,designation) values (default,'James','1996-03-13','Officer');

示例项目

请按照以下步骤创建新项目。

1)打开Eclipse IDE。

2)单击文件菜单,然后选择新建-> Maven项目

3)将显示以下屏幕。
选择创建简单的项目选项,然后单击下一步按钮。

新Maven项目

4)输入任何组ID,工件ID,名称和描述。

Maven项目配置

单击完成按钮。

5)在MySQL的pom.xml中添加以下依赖项。

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.49</version>
</dependency>

6)右键单击项目,选择Maven->更新项目->确定。
它将下载所有依赖项。

1)Apache Commons DBCP 2

DBCP来自Apache Common Project。
DBCP 2.7需要Java8。
要使用DBCP 2,您需要在项目中添加以下依赖项。

<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-dbcp2</artifactId>
	<version>2.7.0</version>
</dependency>

Apache DBCP 2.0提供两种类型的数据源(BasicDataSource和PoolingDataSource)。

BasicDataSource:顾名思义,它很简单,适合大多数常见用例。
它在内部为我们创建PoolingDataSource。

让我们看一下初始化连接池的以下步骤。

  • 创建一个BasicDataSource实例
  • 指定JDBC网址,数据库用户名和密码
  • 指定最小空闲连接数(随时需要保留在池中的最小连接数)
  • 指定最大空闲连接数(池中最大空闲连接数)
  • 指定最大连接总数。
package com.theitroad.example;

/**
 * Java JDBC Connection pool using Apache commons DBCP2 example program
 * 
 * @author pankaj
 */

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.commons.dbcp2.BasicDataSource;

public class DBCP2Demo {

	private static BasicDataSource dataSource = null;

	static {
		dataSource = new BasicDataSource();
		dataSource.setUrl("jdbc:mysql://localhost:3306/empdb?useSSL=false");
		dataSource.setUsername("root");
		dataSource.setPassword("root");

		dataSource.setMinIdle(5);
		dataSource.setMaxIdle(10);
		dataSource.setMaxTotal(25);

	}

public static void main(String[] args) throws SQLException {
		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			connection = dataSource.getConnection();
			statement = connection.createStatement();
			resultSet = statement.executeQuery("select * from tblemployee");
			while (resultSet.next()) {
				System.out.println("empId:" + resultSet.getInt("empId"));
				System.out.println("empName:" + resultSet.getString("empName"));
				System.out.println("dob:" + resultSet.getDate("dob"));
				System.out.println("designation:" + resultSet.getString("designation"));
			}
		} finally {

			resultSet.close();
			statement.close();
			connection.close();
		}
	}

}

输出:

empId:1
empName:Adam
dob:1998-08-15
designation:Manager
empId:2
empName:Smith
dob:2001-01-11
designation:Clerk
empId:3
empName:James
dob:1996-03-13
designation:Officer

PoolingDataSource:它提供了更大的灵活性。
您只需要更改创建DataSource的代码即可。
其余代码将保持不变。

让我们看一下初始化连接池的以下步骤:

  • 使用JDBC URL创建ConnectionFactory的实例。

  • 使用在步骤1中创建的ConnectionFactory实例创建PoolableConnectionFactory实例

  • 创建GenericObjectPoolConfig的实例并设置最大空闲,最小空闲和最大连接属性

  • 现在使用在步骤2和步骤3中创建的实例初始化ObjectPool

  • 现在将pool设置为PoolableConnectionFactory的实例

  • 最后,初始化一个数据源实例

private static DataSource dataSource = null;

	static {

		Properties properties = new Properties();
		properties.setProperty("user", "root");
		properties.setProperty("password", "root");

		ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:mysql://localhost:3306/empdb",
				properties);

		PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null);

		GenericObjectPoolConfig<PoolableConnection> config = new GenericObjectPoolConfig<>();
		config.setMaxTotal(25);
		config.setMaxIdle(10);
		config.setMinIdle(5);

		ObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(poolableConnectionFactory, config);
		poolableConnectionFactory.setPool(connectionPool);

		dataSource = new PoolingDataSource<>(connectionPool);

	}

2)HikariCP

HikariCP快速,可靠且简单。
它是连接池的首选解决方案之一。
诸如Spring Boot 2.x之类的框架将其用作默认连接管理器。

要使用HikariCP,请在我们项目的pom.xml中添加以下依赖项。

<dependency>
	<groupId>com.zaxxer</groupId>
	<artifactId>HikariCP</artifactId>
	<version>3.4.5</version>
</dependency>

HikariCP配置:

我们可以使用下面的示例程序所示的基于Java的配置,也可以使用属性文件来配置HikariCP。
让我们看一下以下属性。

  • idleTimeout:连接对象可以保持空闲状态的时间(以毫秒为单位)。
    它与minimumIdle和maximumPoolSize属性一起使用。
    在指定的时间后,将释放连接对象。

  • connectionTimeout:客户端等待池中的连接对象的时间(以毫秒为单位)。
    如果达到时间限制,则将引发SQL异常。

  • autoCommit:我们可以指定true或者false,如果将其设置为true,则它将自动提交您执行的每个SQL语句;如果将其设置为false,则需要手动提交SQL语句

  • cachePrepStmts:为"准备"语句启用缓存

  • minimumIdle:随时需要在池中保留最少数量的连接对象。

  • maximumPoolSize:可以保留在池中的最大连接数。

package com.theitroad.example;

/**
 * Java JDBC Connection pool using HikariCP example program
 * 
 * @author pankaj
 */

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

public class HikariCPDemo {

	private static HikariDataSource dataSource = null;

	static {
		HikariConfig config = new HikariConfig();
		config.setJdbcUrl("jdbc:mysql://localhost:3306/empdb");
		config.setUsername("root");
		config.setPassword("root");
		config.addDataSourceProperty("minimumIdle", "5");
		config.addDataSourceProperty("maximumPoolSize", "25");

		dataSource = new HikariDataSource(config);
	}

	public static void main(String[] args) throws SQLException {
		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			connection = dataSource.getConnection();
			statement = connection.createStatement();
			resultSet = statement.executeQuery("select * from tblemployee");
			while (resultSet.next()) {
				System.out.println("empId:" + resultSet.getInt("empId"));
				System.out.println("empName:" + resultSet.getString("empName"));
				System.out.println("dob:" + resultSet.getDate("dob"));
				System.out.println("designation:" + resultSet.getString("designation"));
			}
		} finally {
			resultSet.close();
			statement.close();
			connection.close();
		}
	}
}

输出:

empId:1
empName:Adam
dob:1998-08-15
designation:Manager
empId:2
empName:Smith
dob:2001-01-11
designation:Clerk
empId:3
empName:James
dob:1996-03-13
designation:Officer

3)C3P0

C3P0是最古老的库之一。
通常,它与Hibernate一起使用。
要使用C3P0,我们需要向项目添加以下依赖项。

<dependency>
	<groupId>com.mchange</groupId>
	<artifactId>c3p0</artifactId>
	<version>0.9.5.5</version>
</dependency>

我们可以使用C3P0配置以下属性。

  • driverClass:首选的Jdbc驱动程序

  • jdbcUrl:数据库的JDBC Url。

  • initialPoolSize:启动时在池中创建的连接数。

  • acquisitionIncrement:当前大小不足时,需要创建新的连接数。

  • maxIdleTime:连接可以保留在池中而不使用的秒数。

  • maxPoolSize:可以保留在Pool中的最大连接数。

  • minPoolSize:随时需要在Pool中保留最少数量的连接对象。

package com.theitroad.example;

/**
 * Java JDBC Connection pool using C3PO example program
 * 
 * @author pankaj
 */

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Demo {

	static ComboPooledDataSource comboPooledDataSource = null;

	static {
		comboPooledDataSource = new ComboPooledDataSource();

		comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/empdb?useSSL=false");
		comboPooledDataSource.setUser("root");
		comboPooledDataSource.setPassword("root");

		comboPooledDataSource.setMinPoolSize(3);
		comboPooledDataSource.setAcquireIncrement(3);
		comboPooledDataSource.setMaxPoolSize(30);

	}

public static void main(String[] args) throws SQLException {
		Connection connection = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			connection = comboPooledDataSource.getConnection();
			statement = connection.createStatement();
			resultSet = statement.executeQuery("select * from tblemployee");
			while (resultSet.next()) {
				System.out.println("empId:" + resultSet.getInt("empId"));
				System.out.println("empName:" + resultSet.getString("empName"));
				System.out.println("dob:" + resultSet.getDate("dob"));
				System.out.println("designation:" + resultSet.getString("designation"));
			}
		} finally {
			resultSet.close();
			statement.close();
			connection.close();
		}
	}

}

输出:

Aug 29, 2017 8:59:05 PM com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource 
INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1hge9kqacgbp7hjpftse6|77a567e1, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> null, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1hge9kqacgbp7hjpftse6|77a567e1, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/empdb?useSSL=false, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 30, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=**, password=**}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]

empId:1
empName:Adam
dob:1998-08-15
designation:Manager
empId:2
empName:Smith
dob:2001-01-11
designation:Clerk
empId:3
empName:James
dob:1996-03-13
designation:Officer