Java 中的连接池

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

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

连接池

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

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

有了Java,我们就有了一套现成的库。我们只需要配置几个属性就可以使用它们。

Java应用中的连接池

让我们来看看下面的库:

  • ApacheCommons DBCP 2
  • HikariCP
  • C3P0

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

  • 数据库脚本
 1create database empdb;
 2
 3use empdb;
 4
 5create table tblemployee(
 6                    empId integer AUTO_INCREMENT primary key,
 7                    empName varchar(64),
 8                    dob date,
 9                    designation varchar(64)
10);
11
12insert into tblemployee(empId,empName,dob,designation) values (default,'Adam','1998-08-15','Manager');
13insert into tblemployee(empId,empName,dob,designation) values (default,'Smith','2001-01-11','Clerk');
14insert into tblemployee(empId,empName,dob,designation) values (default,'James','1996-03-13','Officer');

示例项目

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

1.打开Eclipse IDE。 2.点击[文件]菜单,选择[新建]->[Maven项目 3.将显示以下屏幕。选择Create a Simple Project选项并单击Next按钮。

New Maven Project

4.输入任意组ID、组ID、名称和说明。

Maven Project Configs

单击完成按钮。

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

1<dependency>
2    <groupId>mysql</groupId>
3    <artifactId>mysql-connector-java</artifactId>
4    <version>5.1.49</version>
5</dependency>

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

1)APACHE Commons DBCP 2

DBCP来自ApacheCommon Project。DBCP 2.7需要Java 8。要使用DBCP 2,您需要在项目中添加以下依赖项。

1<dependency>
2    <groupId>org.apache.commons</groupId>
3    <artifactId>commons-dbcp2</artifactId>
4    <version>2.7.0</version>
5</dependency>

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

BasicDataSource: 顾名思义,简单,适用于最常见的用例。它在内部为我们创建了PoolingDataSource。

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

1.创建BasicDataSource的实例 2.指定JDBC URL、数据库用户名和密码 3.指定空闲连接的最小数量(任何时候需要保留在池中的最小连接数量) 4.指定最大空闲连接数(池中最大空闲连接数) 5.指定最大连接总数。

 1package com.journaldev.example;
 2
 3/**
 4 * Java JDBC Connection pool using Apache commons DBCP2 example program
 5 * 
 6 * @author pankaj
 7 */
 8
 9import java.sql.Connection;
10import java.sql.ResultSet;
11import java.sql.SQLException;
12import java.sql.Statement;
13
14import org.apache.commons.dbcp2.BasicDataSource;
15
16public class DBCP2Demo {
17
18    private static BasicDataSource dataSource = null;
19
20    static {
21    	dataSource = new BasicDataSource();
22    	dataSource.setUrl("jdbc:mysql://localhost:3306/empdb?useSSL=false");
23    	dataSource.setUsername("root");
24    	dataSource.setPassword("root");
25
26    	dataSource.setMinIdle(5);
27    	dataSource.setMaxIdle(10);
28    	dataSource.setMaxTotal(25);
29
30    }
31
32public static void main(String[] args) throws SQLException {
33    	Connection connection = null;
34    	Statement statement = null;
35    	ResultSet resultSet = null;
36    	try {
37    		connection = dataSource.getConnection();
38    		statement = connection.createStatement();
39    		resultSet = statement.executeQuery("select * from tblemployee");
40    		while (resultSet.next()) {
41    			System.out.println("empId:" + resultSet.getInt("empId"));
42    			System.out.println("empName:" + resultSet.getString("empName"));
43    			System.out.println("dob:" + resultSet.getDate("dob"));
44    			System.out.println("designation:" + resultSet.getString("designation"));
45    		}
46    	} finally {
47
48    		resultSet.close();
49    		statement.close();
50    		connection.close();
51    	}
52    }
53
54}

输出:

 1empId:1
 2empName:Adam
 3dob:1998-08-15
 4designation:Manager
 5empId:2
 6empName:Smith
 7dob:2001-01-11
 8designation:Clerk
 9empId:3
10empName:James
11dob:1996-03-13
12designation:Officer

PoolingDataSource: 提供更大的灵活性。您只需更改创建数据源的代码。代码的其余部分将保持不变。

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

1.使用JDBC URL创建ConnectionFactory实例。 2.使用在步骤1中创建的ConnectionFactory实例创建PoolableConnectionFactory实例 3.创建GenericObjectPoolConfig的实例,并设置最大空闲、最小空闲和最大连接属性 4.现在使用在步骤2和步骤3中创建的实例初始化对象池 5.现在将池设置为PoolableConnectionFactory的实例 6.最后,初始化DataSource的实例

 1private static DataSource dataSource = null;
 2
 3    static {
 4
 5    	Properties properties = new Properties();
 6    	properties.setProperty("user", "root");
 7    	properties.setProperty("password", "root");
 8
 9    	ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:mysql://localhost:3306/empdb",
10    			properties);
11
12    	PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null);
13
14    	GenericObjectPoolConfig<PoolableConnection> config = new GenericObjectPoolConfig<>();
15    	config.setMaxTotal(25);
16    	config.setMaxIdle(10);
17    	config.setMinIdle(5);
18
19    	ObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(poolableConnectionFactory, config);
20    	poolableConnectionFactory.setPool(connectionPool);
21
22    	dataSource = new PoolingDataSource<>(connectionPool);
23
24    }

2)HikariCP

HikariCP快速、可靠、简单。它是连接池的首选解决方案之一。像Spring Boot2.x这样的框架使用它作为默认的连接管理器。

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

1<dependency>
2    <groupId>com.zaxxer</groupId>
3    <artifactId>HikariCP</artifactId>
4    <version>3.4.5</version>
5</dependency>

HikariCP配置

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

  • idleTimeout :连接对象可以空闲在池中的时间,单位为毫秒。支持** 最小空闲** 和** 最大池大小** 属性。在指定时间之后,将释放连接对象。
  • ConnectionTimeout :客户端等待来自Pool的连接对象的时间,单位为毫秒。如果达到时间限制,则会抛出SQL异常。
  • AutoCommit :我们可以指定TRUE或FALSE,如果设置为TRUE,它将自动提交您执行的每条SQL语句;如果设置为FALSE,则需要手动提交SQL语句
  • cachePrepStmts:启用准备语句缓存
  • minumIdle:任何时候需要在池中保留的连接对象的最小数量。
  • MaximumPoolSize :池中最大可驻留连接数。
 1package com.journaldev.example;
 2
 3/**
 4 * Java JDBC Connection pool using HikariCP example program
 5 * 
 6 * @author pankaj
 7 */
 8
 9import java.sql.Connection;
10import java.sql.ResultSet;
11import java.sql.SQLException;
12import java.sql.Statement;
13
14import com.zaxxer.hikari.HikariConfig;
15import com.zaxxer.hikari.HikariDataSource;
16
17public class HikariCPDemo {
18
19    private static HikariDataSource dataSource = null;
20
21    static {
22    	HikariConfig config = new HikariConfig();
23    	config.setJdbcUrl("jdbc:mysql://localhost:3306/empdb");
24    	config.setUsername("root");
25    	config.setPassword("root");
26    	config.addDataSourceProperty("minimumIdle", "5");
27    	config.addDataSourceProperty("maximumPoolSize", "25");
28
29    	dataSource = new HikariDataSource(config);
30    }
31
32    public static void main(String[] args) throws SQLException {
33    	Connection connection = null;
34    	Statement statement = null;
35    	ResultSet resultSet = null;
36    	try {
37    		connection = dataSource.getConnection();
38    		statement = connection.createStatement();
39    		resultSet = statement.executeQuery("select * from tblemployee");
40    		while (resultSet.next()) {
41    			System.out.println("empId:" + resultSet.getInt("empId"));
42    			System.out.println("empName:" + resultSet.getString("empName"));
43    			System.out.println("dob:" + resultSet.getDate("dob"));
44    			System.out.println("designation:" + resultSet.getString("designation"));
45    		}
46    	} finally {
47    		resultSet.close();
48    		statement.close();
49    		connection.close();
50    	}
51    }
52}

产出:

 1empId:1
 2empName:Adam
 3dob:1998-08-15
 4designation:Manager
 5empId:2
 6empName:Smith
 7dob:2001-01-11
 8designation:Clerk
 9empId:3
10empName:James
11dob:1996-03-13
12designation:Officer

3)C3P0

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

1<dependency>
2    <groupId>com.mchange</groupId>
3    <artifactId>c3p0</artifactId>
4    <version>0.9.5.5</version>
5</dependency>

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

*driverClass :首选JDBC驱动 *jdbcUrl :数据库的JDBC URL。

  • initialPoolSize:启动时在池中创建的连接数。
  • acquireIncrement:当前大小不够时需要创建的新连接数。 *maxIdleTime :连接在池中不被使用的秒数。 *maxPoolSize :池中最大连接数。
  • minPoolSize:任何时候需要保留在池中的连接对象的最小数量。
 1package com.journaldev.example;
 2
 3/**
 4 * Java JDBC Connection pool using C3PO example program
 5 * 
 6 * @author pankaj
 7 */
 8
 9import java.sql.Connection;
10import java.sql.ResultSet;
11import java.sql.SQLException;
12import java.sql.Statement;
13
14import com.mchange.v2.c3p0.ComboPooledDataSource;
15
16public class C3P0Demo {
17
18    static ComboPooledDataSource comboPooledDataSource = null;
19
20    static {
21    	comboPooledDataSource = new ComboPooledDataSource();
22
23    	comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/empdb?useSSL=false");
24    	comboPooledDataSource.setUser("root");
25    	comboPooledDataSource.setPassword("root");
26
27    	comboPooledDataSource.setMinPoolSize(3);
28    	comboPooledDataSource.setAcquireIncrement(3);
29    	comboPooledDataSource.setMaxPoolSize(30);
30
31    }
32
33public static void main(String[] args) throws SQLException {
34    	Connection connection = null;
35    	Statement statement = null;
36    	ResultSet resultSet = null;
37    	try {
38    		connection = comboPooledDataSource.getConnection();
39    		statement = connection.createStatement();
40    		resultSet = statement.executeQuery("select * from tblemployee");
41    		while (resultSet.next()) {
42    			System.out.println("empId:" + resultSet.getInt("empId"));
43    			System.out.println("empName:" + resultSet.getString("empName"));
44    			System.out.println("dob:" + resultSet.getDate("dob"));
45    			System.out.println("designation:" + resultSet.getString("designation"));
46    		}
47    	} finally {
48    		resultSet.close();
49    		statement.close();
50    		connection.close();
51    	}
52    }
53
54}

产出:

 1Aug 29, 2020 8:59:05 PM com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource 
 2INFO: 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 ]
 3
 4empId:1
 5empName:Adam
 6dob:1998-08-15
 7designation:Manager
 8empId:2
 9empName:Smith
10dob:2001-01-11
11designation:Clerk
12empId:3
13empName:James
14dob:1996-03-13
15designation:Officer

这就是JDBC连接池示例教程,我希望这里没有遗漏任何重要的东西。

参考资料HikariCPAPACHE Commons DBCPC3P0

Published At
Categories with 技术
Tagged with
comments powered by Disqus