Java中的连接池
连接池是指连接对象池。
连接池基于对象池设计模式。
当创建新对象的成本(时间和资源,如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

