C3P0数据库连接池技术详解及实战

news/2025/3/18 11:24:02/

1. 引言

在现代Java开发中,数据库访问是至关重要的一环。传统的JDBC连接方式由于频繁创建和销毁数据库连接,导致性能低下,资源占用过多。为了解决这一问题,数据库连接池(Connection Pool)技术应运而生。
C3P0 作为 Java 领域中一款优秀的数据库连接池框架,提供了高效的连接管理,广泛应用于企业级项目中。本文将深入探讨 C3P0 的技术原理、配置方式,并结合代码示例进行实战演示。

 1.1 类图分析:

这个类图体现了一套用于管理池化数据源(PooledDataSource)的设计:

  • DataSourceCommonDataSource:定义了基础数据源接口。

  • PooledDataSourcePoolBackedDataSourceBaseAbstractPoolBackedDataSource:实现池化数据源。

  • AbstractComboPooledDataSourceComboPooledDataSource:提供组合数据源管理。

  • IdentityTokenized 及相关接口 说明数据源可能涉及身份管理和引用管理。

从结构上看,这是一个用于数据库连接池或资源池管理的框架,类似于 c3p0HikariCP 这类数据库连接池的实现。

2. 传统 JDBC 连接方式的弊端

2.1 连接创建成本高

每次数据库访问时,传统 JDBC 方式都会经历:

  • 加载数据库驱动
  • 创建新连接(Connection)
  • 执行 SQL 语句
  • 关闭连接

由于数据库连接的创建需要进行网络通信、身份验证等操作,连接建立通常需要数十到数百毫秒,在高并发情况下,系统会因频繁创建和销毁连接而性能下降,甚至崩溃

2.2 连接泄露

如果开发人员未能正确关闭数据库连接(Connection),会导致连接资源无法释放,最终引发内存泄露(Memory Leak),甚至造成数据库连接池耗尽,影响整个系统的正常运行。

2.3 无法控制最大连接数

数据库有最大连接数限制(如 MySQL 默认最大 151),如果程序无节制地创建连接,超出数据库负载能力,会导致新连接请求被拒绝,应用系统出现 Too many connections 异常。

 

3. C3P0 数据库连接池

3.1 什么是数据库连接池?

数据库连接池(Connection Pool)是一种复用数据库连接的技术,它的核心思想是预先创建并维护一定数量的数据库连接,并在程序需要时提供可用连接,而非每次新建连接

3.2 C3P0 连接池的工作原理
  1. 初始化连接池:启动时创建固定数量的数据库连接(如 10 个),存放在连接池中。
  2. 获取连接:当应用需要访问数据库时,从连接池中取出一个可用 Connection,而不是重新建立连接。
  3. 归还连接:使用完毕后,不会关闭连接,而是归还到连接池,供后续使用。
  4. 连接池管理:C3P0 会动态调整连接数量,并定期检测连接的健康状态,自动回收无效连接。

4. C3P0 连接池的使用

4.1 依赖引入

Maven 中添加 C3P0 依赖:

<dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.5.5</version>
</dependency>

4.2 方式一:手动配置 C3P0

java">package JDBD_resource;import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;public class JDBC_C3P0 {@Testpublic void test1() throws Exception {// 创建 C3P0 连接池ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();// 读取数据库配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\JDBC\\mysql.properties"));String url = properties.getProperty("url");String user = properties.getProperty("user");String password = properties.getProperty("password");String driver = properties.getProperty("driver");// 设置连接池参数comboPooledDataSource.setDriverClass(driver);comboPooledDataSource.setJdbcUrl(url);comboPooledDataSource.setUser(user);comboPooledDataSource.setPassword(password);comboPooledDataSource.setMinPoolSize(10);  // 最小连接数comboPooledDataSource.setMaxPoolSize(50);  // 最大连接数// 测试连接池性能long start = System.currentTimeMillis();for (int i = 0; i < 5000000; i++) {Connection connection = comboPooledDataSource.getConnection();connection.close();}long end = System.currentTimeMillis();System.out.println("C3P0 连接池 5000 次连接耗时=" + (end - start) + "ms");}
}

运行结果示例 耗时=6139ms:

4.3 方式二:基于 C3P0 配置文件

src/c3p0-config.xml 配置 C3P0,文件名不能更改,否则不能找到配置文件:

<?xml version="1.0" encoding="UTF-8"?><c3p0-config><default-config><property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/MyDatabase?serverTimezone=UTC</property><property name="user">root</property><property name="password">1314</property><property name="initialPoolSize">10</property><property name="maxIdleTime">30</property><property name="maxPoolSize">100</property><property name="minPoolSize">10</property></default-config><named-config name="C3P0">  //一定注意这里的文件名<property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/MyDatabase?serverTimezone=UTC</property><property name="user">root</property><property name="password">1314</property><property name="initialPoolSize">10</property><property name="maxIdleTime">30</property><property name="maxPoolSize">100</property><property name="minPoolSize">10</property></named-config>
</c3p0-config>

在 Java 代码中:

java">@Test
public void test2() throws Exception {// 直接读取 C3P0 配置文件ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("C3P0");long start = System.currentTimeMillis();for (int i = 0; i < 500000; i++) {Connection connection = comboPooledDataSource.getConnection();connection.close();}long end = System.currentTimeMillis();System.out.println("C3P0 方式2(500000 次)耗时=" + (end - start) + "ms");
}

运行结果示例//c3p0 的第二种方式 耗时=957ms

可以看出,即使是 50 万次连接请求,C3P0 依然能高效管理数据库连接。

特别对比普通方法进行5000000次的数据库访问,访问时间在3028ms

java">package JDBD_resource;import JDBC.PerparedStatement;
import untils.JDBCutils;import java.sql.Connection;//演示传统的获取connect的弊端
public class JDBC_Connect_Quest {public static void main(String[] args) throws Exception {long start = System.currentTimeMillis();for (int i = 0; i < 5000000; i++) {Connection  connection = JDBCutils.getConnection();
//            connection.close();//这里不关闭连接,模拟在线连接数, 耗时:3028ms}System.out.println("耗时:"+(System.currentTimeMillis() - start));
//        结果
//        Caused by: java.sql.SQLNonTransientConnectionException: Connection exception,
//        SQL-server rejected establishment of SQL-connection,  message from server: "Too many connections"}
}

5. 结论

  1. C3P0 是 Java 领域中最稳定的数据库连接池之一,适用于大部分企业级项目

  2. C3P0 提供了两种使用方式:手动代码配置 & 配置文件方式,均可大幅优化数据库连接管理。

  3. HikariCP 在高并发下性能更优,适用于对数据库访问速度要求较高的系统

希望本文能帮助你理解 C3P0 的工作原理及其在实际开发中的应用


http://www.ppmy.cn/news/1580058.html

相关文章

深度学习-yolo实战项目【分类、目标检测、实例分割】?如何创建自己的数据集?如何对数据进行标注?没有GPU怎么办呢?

一、本地环境配置 &#xff08;1&#xff09;本地创建虚拟环境 &#xff08;2&#xff09;下载项目到本地 &#xff08;3&#xff09;安装依赖 &#xff08;4&#xff09;测试一下 二、电脑没有GPU训练不了怎么办&#xff1f;【不用本地环境】 &#xff08;1&#xff0…

Spring、Spring Boot、Spring Cloud 的区别与联系

1. Spring 框架 定位&#xff1a;轻量级的企业级应用开发框架&#xff0c;核心是 IoC&#xff08;控制反转&#xff09; 和 AOP&#xff08;面向切面编程&#xff09;。 核心功能&#xff1a; 依赖注入&#xff08;DI&#xff09;&#xff1a;通过 Autowired、Component 等注解…

爬虫案例八js逆向爬取网易音乐

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、js逆向的前期准备二、网站分析三、代码 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 爬取网易音乐 提示&#xff1a;以下是本篇…

【春招笔试】2025.03.13-蚂蚁春招笔试题

题目总结 题目一:区间未出现的最小值之和 1️⃣:统计全为1的子数组数量和全为0的子数组数量,利用公式计算 2️⃣:利用数学公式 n(n+1) - 2N0 - N1 计算最终答案 难度:中等 这道题目的关键在于理解 mex 的概念,并发现对于只含 0 和 1 的数组,mex 值只可能是 0、1 或 2。…

365天之第P10周:Pytorch实现车牌识别

365天之第P10周&#xff1a;Pytorch实现车牌识别 Pytorch实现车牌识别 365天之第P10周&#xff1a;Pytorch实现车牌识别一、导入数据1.获取类别名2. 数据可视化3. 标签数字化4. 加载数据文件5. 划分数据 二、自建模型三、 训练模型1. 优化器与损失函数2. 模型训练 四、 结果分析…

如何配置 Docker 以实现无需 sudo 使用

1. 背景知识&#xff1a;为什么需要 sudo&#xff1f; Docker 是一个容器化平台&#xff0c;其核心组件包括&#xff1a; Docker 守护进程&#xff08;dockerd&#xff09;&#xff1a;负责管理容器的创建、运行和销毁。Docker CLI&#xff1a;用户通过命令行工具&#xff08…

DeepSeek-prompt指令-当DeepSeek答非所问,应该如何准确的表达我们的诉求?

当DeepSeek答非所问&#xff0c;应该如何准确的表达我们的诉求&#xff1f;不同使用场景如何向DeepSeek发问&#xff1f;是否有指令公式&#xff1f; 目录 1、 扮演专家型指令2、 知识蒸馏型指令3、 颗粒度调节型指令4、 时间轴推演型指令5、 极端测试型6、 逆向思维型指令7、…

【redis】Jedis 操作 Redis 基础指令(下)

列表操作 lpush/rpush 和 lpop/rpop 将一个或者多个元素从左/右侧放入&#xff08;头/尾插&#xff09;到 list 中 依次头插 从 list 左/右侧取出元素&#xff08;即头/尾删&#xff09; public static void test1(Jedis jedis) { jedis.flushAll(); long n jedis.lpush(…