c3p0、Druid连接池+工具类 Apache-DbUtils (详解!!!)
数据库连接池是在应用程序启动时创建一定数量的数据库连接,并将这些连接存储在池中。当应用程序需要与数据库通信时,它可以向池中请求一个连接,使用完后将连接归还给池,而不是关闭连接。这样可以减少创建和关闭连接的开销,提高应用程序的性能。
一、Apache-DbUtils工具类
Apache DbUtils 是一个简化 JDBC 编程的开源工具类库,它封装了 JDBC API 中的许多重复性任务,如结果集的处理、连接的管理等。DbUtils 提供了几个核心类和接口,帮助开发者更高效地编写数据库访问代码。
1.安装commons-dbutils-1.3.jar
下载官网:DbUtils – Download Apache Commons DbUtils
下载后将jar文件复制粘贴到idea的lib目录
在IDEA中,右击jar包,选择“Add as Library”将其添加到项目库中
2.核心类与接口
类/接口 | 作用 |
---|---|
QueryRunner | QueryRunner 是 DbUtils 中最常用的类之一,它简化了执行 SQL 查询和更新的过程。QueryRunner 使用 DataSource 来获取数据库连接,并在执行完操作后自动关闭连接。 |
ResultSetHandler | ResultSetHandler 是一个接口,用于将 ResultSet 转换为其他对象。DbUtils 提供了多个实现类,如 BeanHandler 、BeanListHandler 、ColumnListHandler 、ScalarHandler 等。 |
DbUtils | 工具类,提供静默关闭连接、提交事务等辅助方法 |
BasicRowProcessor | BasicRowProcessor 是一个用于处理 ResultSet 的类,它负责将 ResultSet 中的数据映射到 Java 对象。BasicRowProcessor 可以与 ResultSetHandler 一起使用。 |
二、c3p0的配置与运用
C3P0是一个开源的JDBC连接池,它实现了数据源和连接池的管理。C3P0提供了很多功能,比如连接测试、自动回收空闲连接、支持多种数据库等等。
下载官网:c3p0:JDBC DataSources/Resource Pools download | SourceForge.net
解压下载的压缩包,所需的jar包位于解压后的lib
目录下,主要包括:
c3p0-0.9.5.5.jar
c3p0-oracle-thin-extras-0.9.5.5.jar
mchange-commons-java-0.2.19.jar
-
添加jar包到IDEA项目:
- 将下载并解压后的jar包文件(如
c3p0-0.9.5.5.jar
和mchange-commons-java-0.2.19.jar
)复制到项目的lib
目录下。 - 在IDEA中,右击这些jar包,选择“Add as Library”将其添加到项目库中
- 将下载并解压后的jar包文件(如
2.创建和配置c3p0-config.xml文件:
- 在项目的
src
目录下新建一个名为c3p0-config.xml
的文件,配置数据库连接池的相关参数。例如:
<c3p0-config>
<named-config name="my">
<!-- 驱动类 -->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<!-- url-->
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/mydb</property>
<!-- 用户名 -->
<property name="user">root</property>
<!-- 密码 -->
<property name="password">root</property>
<!-- 每次增长的连接数-->
<property name="acquireIncrement">5</property>
<!-- 初始的连接数 -->
<property name="initialPoolSize">10</property>
<!-- 最小连接数 -->
<property name="minPoolSize">5</property>
<!-- 最大连接数 -->
<property name="maxPoolSize">10</property>
<!-- 可连接的最多的命令对象数 -->
<property name="maxStatements">5</property>
<!-- 每个连接对象可连接的最多的命令对象数 -->
<property name="maxStatementsPerConnection">2</property>
</named-config>
</c3p0-config>
注意:
(1).我用的mysql是8.0版本所以类名是com.mysql.cj.jdbc.Driver
(2).文件名不要写错了,尽量fic3p0-config.xml
3.使用c3p0连接池+Apache-DbUtils工具类:
例如:c3p0连接池连接MySQL+Apache-DbUtils的QueryRunner类,查询数据
import DAO_.Bean.Student; // 引入Student类
import com.mchange.v2.c3p0.ComboPooledDataSource; // 引入连接池类
import org.apache.commons.dbutils.QueryRunner; // 引入查询运行器类
import org.apache.commons.dbutils.handlers.BeanListHandler; // 引入结果集处理类
import java.beans.PropertyVetoException; // 引入属性否定异常
import java.io.FileInputStream; // 引入文件输入流
import java.io.FileNotFoundException; // 引入文件未找到异常
import java.io.IOException; // 引入IO异常
import java.sql.Connection; // 引入数据库连接接口
import java.sql.SQLException; // 引入SQL异常
import java.util.List; // 引入列表接口
import java.util.Properties; // 引入属性类
public class A {
public static void main(String[] args) {
// 加载配置文件
Properties properties = new Properties();
try (FileInputStream fis = new FileInputStream("src/mysql.properties")) {
properties.load(fis);
} catch (FileNotFoundException e) {
System.err.println("配置文件未找到!");
return;
} catch (IOException e) {
System.err.println("读取配置文件失败!");
return;
}
// 从配置文件中获取数据库连接信息
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
// 创建数据库连接池
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
try {
comboPooledDataSource.setPassword(password);
comboPooledDataSource.setUser(user);
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setInitialPoolSize(50);
comboPooledDataSource.setMaxPoolSize(100);
} catch (PropertyVetoException e) {
System.err.println("设置数据库连接池参数失败!");
return;
}
// 从连接池中获取数据库连接
try (Connection connection = comboPooledDataSource.getConnection()) {
// SQL查询语句
String sql = "select * from t2;";
// 创建查询运行器
QueryRunner queryRunner = new QueryRunner();
// 执行查询,并将结果集转换为Student对象的列表
List<Student> students = queryRunner.query(connection, sql, new BeanListHandler<>(Student.class));
// 遍历并打印学生信息
for (Student student : students) {
System.out.println(student);
}
//关闭连接
connection.close();
} catch (SQLException e) {
System.err.println("数据库操作失败!");
}
}
}
查询结果:
三、Druid连接池的配置与运用
Druid是阿里巴巴开源的数据库连接池,不仅提供连接池管理,还包含强大的监控和扩展能力,性能优秀,尤其适用于高并发场景。
1.安装druid-1.1.10.jar
下载地址:Central Repository: com/alibaba/druid/1.2.23 (maven.org)
和以上连接池一样操作,这里就不演示了
2.创建和配置druid.properties文件:
#key=value
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb?rewriteBatchedStatements=true
#url=jdbc:mysql://localhost:3306/mydb
username=root
password=root
#initial connection Size
initialSize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=20
#max wait time (5000 mil seconds)
maxWait=5000
3.使用Druid连接池+Apache-DbUtils工具类:
例如:Druid连接池连接MySQL+Apache-DbUtils的QueryRunner类,查询数据
import DAO_.Bean.Student; // 引入Student类
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.commons.dbutils.QueryRunner; // 引入查询运行器类
import org.apache.commons.dbutils.handlers.BeanListHandler; // 引入结果集处理类
import javax.sql.DataSource;
import java.io.FileInputStream; // 引入文件输入流
import java.io.FileNotFoundException; // 引入文件未找到异常
import java.io.IOException; // 引入IO异常
import java.sql.Connection; // 引入数据库连接接口
import java.sql.SQLException; // 引入SQL异常
import java.util.List; // 引入列表接口
import java.util.Properties; // 引入属性类
public class Test{
public static void main(String[] args) {
// 加载配置文件
Properties properties = new Properties();
try (FileInputStream fis = new FileInputStream("src/druid.properties")) {
properties.load(fis);
} catch (FileNotFoundException e) {
System.err.println("配置文件未找到!");
return;
} catch (IOException e) {
System.err.println("读取配置文件失败!");
return;
}
Connection connection;
// 创建数据库连接池
try {
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
connection = dataSource.getConnection();
} catch (Exception e) {
throw new RuntimeException(e);
}
// 从连接池中获取数据库连接
try {
// SQL查询语句
String sql = "select * from t2;";
// 创建查询运行器
QueryRunner queryRunner = new QueryRunner();
// 执行查询,并将结果集转换为Student对象的列表
List<Student> students = queryRunner.query(connection, sql, new BeanListHandler<>(Student.class));
// 遍历并打印学生信息
for (Student student : students) {
System.out.println(student);
}
//关闭连接
connection.close();
} catch (SQLException e) {
System.err.println("数据库操作失败!");
}
}
}
查询结果:
补充:Druid连接池的二次封装-->DruidUtil
package DAO_.Utils;
import com.alibaba.druid.pool.DruidDataSourceFactory; // 导入Druid数据源工厂类
import javax.sql.DataSource; // 导入数据源接口
import java.io.FileInputStream; // 导入文件输入流类
import java.sql.Connection; // 导入数据库连接接口
import java.sql.ResultSet; // 导入结果集接口
import java.sql.SQLException; // 导入SQL异常类
import java.sql.Statement; // 导入SQL语句接口
import java.util.Properties; // 导入属性类
public class DruidUtil {
private static DataSource dataSource; // 定义数据源对象,用于获取数据库连接
static {
Properties properties = new Properties(); // 创建属性对象,用于加载配置文件
try {
properties.load(new FileInputStream("src\\druid.properties")); // 加载配置文件
dataSource = DruidDataSourceFactory.createDataSource(properties); // 根据配置文件创建数据源
} catch (Exception e) {
throw new RuntimeException(e); // 如果出现异常,抛出运行时异常
}
}
/**
* 获取数据库连接
*
* @return 数据库连接对象
* @throws SQLException 如果获取连接失败,抛出SQL异常
*/
public static Connection getconnection() throws SQLException {
return dataSource.getConnection(); // 从数据源获取数据库连接
}
/**
* 关闭数据库资源
*
* @param resultSet 结果集对象
* @param connection 数据库连接对象
* @param statement SQL语句对象
*/
public static void close(ResultSet resultSet, Connection connection, Statement statement) {
try {
if (resultSet != null) {
resultSet.close(); // 如果结果集对象不为空,则关闭结果集
}
if (connection != null) {
connection.close(); // 如果连接对象不为空,则关闭连接
}
if (statement != null) {
statement.close(); // 如果语句对象不为空,则关闭语句
}
} catch (SQLException e) {
throw new RuntimeException(e); // 如果关闭过程中出现异常,抛出运行时异常
}
}
}
封装好的方法可以直接调用连接和关闭
例如:
@Test
// 使用BeanListHandler来处理查询结果,将每行数据转换为Student对象,并存储在ArrayList集合中返回
public void test() throws SQLException {
Connection connection = DruidUtil.getconnection(); // 获取数据库连接
String sql = "select * from t2 where id =?"; // 定义SQL查询语句,参数占位符为?
QueryRunner queryRunner = new QueryRunner(); // 创建QueryRunner对象,用于执行SQL语句
// 执行查询操作,将结果集转换为List<Student>对象
// 参数说明:connection - 数据库连接对象;sql - SQL查询语句;new BeanListHandler<Student>(Student.class) - 结果集处理方式,将每行数据转换为Student对象;1 - SQL语句中的参数值,对应占位符?
List<Student> students = queryRunner.query(connection, sql, new BeanListHandler<Student>(Student.class), 1);
// 遍历List集合,打印每个Student对象
for (Student student : students) {
System.out.println(student);
}
// 关闭数据库连接,释放资源
// 参数说明:null - 结果集对象,此处为null because no ResultSet is used;connection - 数据库连接对象;null - SQL语句对象,此处为null because no Statement is explicitly created
DruidUtil.close(null, connection, null);
}
四、C3P0与Druid的比较
-
性能:
- Druid在高并发环境下性能优于C3P0。
-
扩展性:
- Druid支持过滤器机制,易于扩展功能,如SQL日志记录、权限控制等。
- C3P0的扩展性不如Druid。
-
配置复杂度:
- C3P0配置相对简单,易于上手。
- Druid配置较为复杂,学习曲线较陡。
比较的代码:
测试c3p0连接MySQL50万次:
@Test
// 测试使用c3p0连接池获取数据库连接
public void TestPool() throws IOException, PropertyVetoException, SQLException {
Properties properties = new Properties();
// 加载配置文件
properties.load(new FileInputStream("src\\mysql.properties"));
// 从配置文件中获取数据库连接信息
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
// 创建c3p0连接池数据源实例
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
// 设置数据库连接驱动
comboPooledDataSource.setDriverClass(driver);
// 设置数据库用户名
comboPooledDataSource.setUser(user);
// 设置数据库URL
comboPooledDataSource.setJdbcUrl(url);
// 设置数据库密码
comboPooledDataSource.setPassword(password);
// 设置连接池的初始大小
comboPooledDataSource.setInitialPoolSize(50);
// 设置连接池的最大大小
comboPooledDataSource.setMaxPoolSize(100);
// 记录开始时间
long l = System.currentTimeMillis();
// 循环获取和释放连接,测试连接池性能
for (int i = 0; i < 500000; i++) {
Connection connection = comboPooledDataSource.getConnection(user, password);
connection.close();
}
// 记录结束时间
long l1 = System.currentTimeMillis();
// 打印连接池获取连接所需的总时间
System.out.println("连接的时间:"+(l1-l));
}
结果:
测试druid连接MySQL50万次:
@Test
// 测试使用druid连接池获取数据库连接
public void testDruid() throws Exception {
Properties properties = new Properties();
// 加载druid连接池配置文件
properties.load(new FileInputStream("src\\druid.properties"));
// 使用DruidDataSourceFactory创建数据源实例
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
// 记录开始时间
long l = System.currentTimeMillis();
// 循环获取和释放连接,测试连接池性能
for (int i = 0; i < 500000; i++) {
Connection connection = dataSource.getConnection();
connection.close();
}
// 记录结束时间
long l1 = System.currentTimeMillis();
// 打印连接池获取连接所需的总时间
System.out.println("时间是:"+(l1-l));
}
结果: