数据库连接池常见使用介绍
1.1 数据库连接池的价值
数据库的连接是一种宝贵的数据库资源,原生JDBC不断获取和释放连接等操作在简单应用中体现不出性能、稳定性等问题,而在企业应用或者多用户并发访问的大型应用中,稳定、性能可靠的数据库操作显得尤为重要,为此数据库连接池应运而生。
Java提供了连接池接口规范(javax.sql.DataSource),也是面向接口开发的应用。
数据库连接池针对连接进行管理,包括:
- 基本配置:提供数据库连接驱动、URL、用户名、密码
- 关键配置:初始化、最大、最小、最大等待时间
- 性能配置:预缓存、连接有效性检测、超时连接关闭
- 常用操作方法:获取、归还连接方法等
备注:本文主要目的是对数据库连接池解决的问题有较深的认识,以及会使用常见的连接池完成应用开发,对于连接池的内部实现机制和性能优化后续有必要再探讨。
1.2 常见的数据库连接池以及用法举例
1.2.1 常见数据库连接池
- DBCP连接池:tomcat内置数据源
- C3P0连接池: 开源的连接池,spring、Hibernate使用
- Druid连接池:阿里自研号称为监控而生的连接池,由于经过淘宝天猫双11等实战检验,是目前性能、稳定性、扩展性等最好的连接池,后续之余可以单独深入学习探讨下。
1.2.2 各连接池的用法举例
1.2.2.1 DBCP连接池实现样例
- 步骤分析
- 导包:commons-dbcp…jar & commons-pool…jar(演示是通过maven项目,通过关键字配置pom导包)
- 编写DBCP工具类
通过私有静态变量定义基础配置信息+数据源实现类(BasicDataSource),通过静态代码块进行以上变量初始化,随后提供静态方法:获取连接、归还连接。
- 编写测试类进行测试(最后三种方式统一测试,只换一行代码而已)
- DBCP工具类编写-代码示例
public class DBCPUtils {
private static BasicDataSource basicDataSource = null;
private static String url = "jdbc:mysql://数据库IP:3306/test?characterEncoding=utf-8";
private static String driverClassName = "com.mysql.jdbc.Driver";
private static String username = "root";
private static String password = "root";
static {
basicDataSource = new BasicDataSource();
basicDataSource.setUrl(url);
basicDataSource.setDriverClassName(driverClassName);
basicDataSource.setUsername(username);
basicDataSource.setPassword(password);
}
public static Connection getConnection() throws SQLException {
return basicDataSource.getConnection();
}
public static void close(Connection connection, Statement statement) throws SQLException {
if(statement != null){
statement.close();
}
if(connection != null){
connection.close();
}
}
public static void close(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
if(resultSet != null){
resultSet.close();
}
if(statement != null){
statement.close();
}
if(connection != null){
connection.close();
}
}
}
1.2.2.2 C3P0连接池实现样例
- 步骤分析
- 导包:c3po-…jar & mchange-commons-java-…jar
- 编写c3p0-config.xml
特别说明:
c3p0连接池会自动加载配置文件,配置文件命名不可更改,这是约定/使用规范,具体配置没有必要记忆,能看懂会配置为原则。另外除了默认的一套配置,还可以配置其他多套数据源配置,在实现类(ComboPooledDataSource)实例化时指定引用的配置名称即可,本例中配置了,届时应用mysql即可。
- 编写工具类
- 编写测试方法进行测试(最后三种方式统一测试,只换一行代码而已)
- 代码示例
c3p0-config.xml配置:
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://数据库IP:3306/test?characterEncoding=UTF-8</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- initialPoolSize:初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。 -->
<property name="initialPoolSize">5</property>
<!-- maxIdleTime:最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。-->
<property name="maxIdleTime">60</property>
<!-- maxPoolSize:连接池中保留的最大连接数 -->
<property name="maxPoolSize">100</property>
<!-- minPoolSize: 连接池中保留的最小连接数 -->
<property name="minPoolSize">5</property>
</default-config>
<!--配置连接池mysql-->
<named-config name="mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://数据库IP:3306/test?characterEncoding=UTF-8</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">5</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">5</property>
</named-config>
<!--配置连接池2,可以配置多个-->
</c3p0-config>
C3P0工具类代码示例:
public class C3P0Utils {
private static ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("mysql");
public static Connection getConnection() throws SQLException {
return comboPooledDataSource.getConnection();
}
public static void close(Connection connection, Statement statement) throws SQLException {
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
}
public static void close(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
}
}
1.2.2.3 Druid连接池实现样例
- 步骤分析
- 导包:druid…jar
- 编写properties配置文件
特别说明: Druid数据源通过properties配置方式加载配置项,且配置文件命名不要求。
- 编写DruidUtils工具类
通过静态代码块初始化,properties配置文件,以及通过DruidDataSourceFactory类获取数据源。
- 编写测试方法进行测试(最后三种方式统一测试,只换一行代码而已)
- 代码示例
Druid.properties配置:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://数据库IP:3306/test?characterEncoding=UTF-8
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
Druid工具类代码示例:
public class DruidUtils {
private static Properties properties = null;
private static DataSource dataSource = null;
static {
InputStream inputStream = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
properties = new Properties();
try {
properties.load(inputStream);
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void close(Connection connection, Statement statement) throws SQLException {
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
}
public static void close(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
}
}
1.2.2.4 三种连接池测试
由于以上针对三种常见数据源进行了工具类封装,测试方法中只是调用类似的静态方法来测试。
测试代码示例:
import jdbc.utils.C3P0Utils;
import jdbc.utils.DBCPUtils;
import jdbc.utils.DruidUtils;
import org.junit.Test;
import java.sql.*;
/**
* @author fengqingyang
* @create 2022-05-26 18:23
*/
public class JDBCConnPoolTest {
@Test
public void testConnPools() {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 连接池1:使用DBCP连接池
//connection = DBCPUtils.getConnection();
// 连接池2: 使用c3p0连接池
//connection = C3P0Utils.getConnection();
// 连接池3:使用druid连接池
connection = DruidUtils.getConnection();
String sql = "select * from citizen";
statement = connection.prepareStatement(sql);
resultSet = ((PreparedStatement)statement).executeQuery();
while(resultSet.next()){
String cust_name = resultSet.getString("cust_name");
System.out.println("cust_name=" + cust_name);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//DBCPUtils.close(connection, statement, resultSet);
//C3P0Utils.close(connection, statement, resultSet);
DruidUtils.close(connection, statement, resultSet);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
至此,三种常见的数据库连接池介绍和演示完毕,感谢!