首页 > 编程笔记 > Java笔记 阅读:20

Java C3P0数据库连接池技术的用法(附带实例)

在开发基于数据库的程序时,传统模式访问数据库基本按照这几个步骤进行:
这种开发模式存在一定的问题,因为 JDBC 的数据库连接对象使用 DriverManager 来获取,每次建立数据库连接时都要将连接对象加载到内存中,然后再验证用户名和密码,这个过程需要花费 0.05~1s 的时间,用完之后还需要把连接释放掉,非常消耗服务器资源。

若同时有几十万人甚至上百万人在线,那么频繁地创建数据库连接将占用很多的系统资源,严重时会造成服务器的崩溃。

为了解决传统开发中的数据库连接问题,可以采用数据库连接池技术。该技术负责分配、管理和释放数据库连接,它允许程序重复使用一个现有的数据库连接,而不是每次新建一个。

数据库连接池技术在初始化时会创建一定数量的数据库连接对象并放到连接池中,这些数据库连接的数量可以通过最小数据库连接数来设定。无论连接池中的连接是否被使用,连接池都将一直保证至少有一定数量的数据库连接。另外,连接池技术通过最大数据库连接数量来限定连接池能创建的最大连接数,当应用程序向连接池请求的连接数超过连接池限定的最大连接数时,这些请求将被加入到等待队列中,直到连接池中有空闲连接时,再分配给这些请求。

目前,使用比较普遍的两种开源的数据库连接池库组件是 DBCP 和 C3P0,本节详细讲解 C3P0 连接池的用法。

C3P0 是一个开源的数据库连接池,它实现了数据源和 JNDI 绑定,支持 JDBC3 规范和 JDBC2 的标准扩展。目前,使用 C3P0 的开源项目有 HibernateSpring 等。

在使用 C3P0 连接池时,需要引入 jar 文件 c3p0-0.9.5.2.jar和mchange-commons-java-0.2.11.jar。

除此之外,还需要在项目的 src 根目录下创建一个 C3P0 连接池需要的 xml 配置文件,这个 xml 配置文件的名字必须定义为 c3p0-config.xml。配置文件中配置的各项参数如下表所示。

表:C3P0 连接池配置参数
参数 参数描述
maxPoolSize 连接池中拥有的最大连接数,如果获得新连接时使连接总数超过这个值则不会再获取新连接,而是等待其他连接释放
minPoolSize 连接池保持的最小连接数
initialPoolSize 连接池初始化时创建的连接数
maxIdleTime 连接的最大空闲时间,如果超过这个时间,某个数据库连接还没有被使用,则会断开掉这个连接
driverClassName JDBC 数据库驱动类的类名
jdbcUrl 连接路径
user 数据库用户名
password 数据库密码

接下来,通过案例来演示 C3P0 连接池的使用。

【实例】以前文创建的数据库 school 为例,使用 C3P0 连接池实现对数据库的访问。在该例中需要创建 C3P0 连接池配置文件 c3p0-config.xml 和代码文件 Demo.java。
1) 在项目的 src 目录下创建 C3P0 连接池配置文件 c3p0-config.xml,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
        <!--数据库驱动类-->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <!--数据库连接地址-->
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf-8&useSSL=false</property>
        <!--数据库用户名-->
        <property name="user">root</property>
        <!--数据库密码-->
        <property name="password">root</property>
        <!--初始连接数-->
        <property name="initialPoolSize">10</property>
        <!--连接最大空闲时间-->
        <property name="maxIdleTime">30</property>
        <!--连接池最大连接数-->
        <property name="maxPoolSize">100</property>
        <!--连接池最小连接数-->
        <property name="minPoolSize">10</property>
    </default-config>
</c3p0-config>

2) 在项目的 src 目录下新建包 com.biancheng.c,并在该包下创建代码文件 Demo.java,实现通过 C3P0 连接池访问数据库,代码如下:
package com.biancheng.c;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class Demo {
    public static void main(String[] args) throws SQLException {
        // 创建C3P0连接池
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        // 从连接池中获取数据库连接
        Connection con = dataSource.getConnection();
        // 定义插入的SQL语句
        String sql = "insert into students " + " (name, gender, age) " + " values" + " ('张三','男',20) ";
        // 创建预编译命令执行对象,绑定插入SQL语句
        PreparedStatement pst = con.prepareStatement(sql);
        // 执行插入操作
        int count = pst.executeUpdate();
        // 输出插入的记录数
        System.out.println("插入的记录数是:" + count);
        // 定义查询的SQL语句
        sql = "select id, name, gender, age from students ";
        // 创建预编译命令执行对象,绑定查询SQL语句
        pst = con.prepareStatement(sql);
        // 执行查询并返回结果集对象
        ResultSet rs = pst.executeQuery();
        System.out.println("查询的结果是:");
        // 通过结果集对象循环遍历查询的表数据
        while (rs.next()) {
            System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getString(3) + " " + rs.getInt(4));
        }
        // 关闭数据库对象
        if (rs != null) {
            rs.close();
        }
        if (pst != null) {
            pst.close();
        }
        if (con != null) {
            con.close(); // 将连接放回连接池
        }
    }
}
程序的运行结果如下:

插入的记录数是: 1
查询的结果是:
1 张三 男 20

实例程序中,首先需要在程序中引入 C3P0 连接池需要的 jar 文件。然后,在 src 根目录下创建一个 xml 配置文件 c3p0-config.xml,在该文件中配置了 C3P0 连接池需要使用的相关参数。

接着,创建了一个测试类,在测试类的 main() 方法中,直接使用 ComboPooledDataSource 创建了 C3P0 连接池的数据源对象 dataSource。然后,使用 dataSource 从连接池中获取一个 Connection 连接对象。通过连接对象创建了 PreparedStatement 对象,并绑定插入的 SQL 语句。

接着,使用 PreparedStatement 对象执行插入操作,向数据库插入记录,并将插入的记录数打印输出。之后,再次通过连接对象创建一个新的 PreparedStatement 对象,并绑定查询的 SQL 语句。

接着,通过 PreparedStatement 对象执行查询操作,并返回一个 ResultSet 结果集对象。然后,使用结果集对象通过循环的方式将查询到的数据逐条输出。最后,依次关闭数据库对象。

需要注意的是,与 DBCP 连接池的用法一样,在调用连接对象的 close() 方法时,连接并没有被销毁,而是被放回到连接池中,下次需要使用时可以直接使用。

相关文章