数据库连接池——C3P0&Druid

数据库连接池基本介绍



1. 基本概念

  数据库连接池的本质上是一个容器(集合),存放数据库连接的容器,当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完后,会将连接对象归还给容器。百度百科介绍
  使用数据库连接池可以:节约资源、提高访问效率。



2. 数据源标准接口 —— javax.sql.DataSource

  DataSource 是一个连接物理数据源的工厂,用于连接到此 DataSource 对象表示的物理数据源 。

  除了用 DriverManager 对象获取数据库连接外,DataSource 对象是获得数据库连接的首选方法。

  DataSource 的 API 介绍


2.1 DataSource 的三种实现类型

实现类型 描述
基本实现 创建一个标准的 Connection 对象。
连接池实现 创建一个 Connection 对象,该对象将自动参与连接池。
分布式事务实现 创建一个 Connection 可用于分布式事务的对象

2.2 部分相关的方法及描述

方法名 描述
Connection getConnection() 尝试与数据源建立连接,返回连接对象。
Connection getConnection​(String username, String password) 尝试与数据源建立连接,返回连接对象。
void close() 归还该 Connection 对象的数据库 和 JDBC资源。
PrintWriter getLogWriter() 检索此 DataSource 对象的日志编写器。


2.3 C3P0 数据库连接池

  C3P0是一个开源的JDBC连接池,目前使用它的开源项目有Hibernate、Spring等。

  C3P0 百度百科

  C3P0 API 文档


2.3.1 使用步骤

  1. 导入jar包

    • C3P0 jar包下载地址
    • mysql-connector-java-8.0.17.jar : 注意与自己装的数据库版本对应。
    • c3p0-0.9.5.2.jar
    • mchange-commons-java-0.2.11.jar
  2. 定义配置文件

    • 命名固定:c3p0.properties 或 c3p0-config.xml
    • 放置路径:src 路径下
    • 配置内容可以查看百度百科,后文会简单介绍几个。
  3. 创建核心对象

    • ComboPooledDataSource
  4. 获取连接对象

    • 方法:getConnection
  5. 获取连接对象后就可以进行其他JDBC相关的操作了,这里不再演示。


2.3.2 配置文件

<?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://localhost:3306/demo_test?serverTimezone=UTC</property>
		<property name="user">root</property>
		<property name="password">root</property>

        <!--连接池参数-->
        <!--初始化申请的连接数量-->
		<property name="initialPoolSize">10</property>
        <!--最大的连接池数量-->
		<property name="maxPoolSize">10</property>
        <!--超时时间,单位为毫秒-->
		<property name="checkoutTimeout">3000</property>
	</default-config>

	<!-- 命名配置 -->
	<named-config name="otherc3p0">
		<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC</property>
		<property name="user">root</property>
		<property name="password">root</property>

		<property name="initialPoolSize">5</property>
		<property name="maxPoolSize">8</property>
		<property name="checkoutTimeout">3000</property>
	</named-config>
</c3p0-config>

注意数据库参数配置:

  • mysql 5.0 的驱动路径为:com.mysql.jdbc.Driver
  • MySQL 8.0 的驱动路径为:com.mysql.cj.jdbc.Driver
  • MySQL 8.0 之后必须加 : ?serverTimezone=UTC
    • 如:jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC
    • 否则会报错时区错误。

2.3.3 Java代码基本演示:获取连接对象并打印到控制台

package com.base.datasource.c3p0;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class C3P0Demo1 {
    public static void main(String[] args) throws SQLException {
        //1.1 获取DataSource,使用默认配置
        // DataSource ds = new ComboPooledDataSource();
        //1.2 获取连接对象
        // Connection conn = ds.getConnection();
        //3. 打印
       // System.out.println(conn);

        // 2.1 获取DataSource,使用指定名称的配置
        DataSource ds = new ComboPooledDataSource("otherc3p0");
        for (int i=1;i<=10;i++){
            // 2.2 获取连接对象
            Connection conn = ds.getConnection();
            // 2.2 打印
            System.out.println(i +" : "+ conn);
            if (i == 5){
                conn.close();
            }
        }
    }
}

运行结果:

1 : com.mchange.v2.c3p0.impl.NewProxyConnection@6a5fc7f7 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@3b6eb2ec]
2 : com.mchange.v2.c3p0.impl.NewProxyConnection@6e8dacdf [wrapping: com.mysql.cj.jdbc.ConnectionImpl@7a79be86]
3 : com.mchange.v2.c3p0.impl.NewProxyConnection@b684286 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@880ec60]
4 : com.mchange.v2.c3p0.impl.NewProxyConnection@7f63425a [wrapping: com.mysql.cj.jdbc.ConnectionImpl@36d64342]
5 : com.mchange.v2.c3p0.impl.NewProxyConnection@511baa65 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@340f438e]
6 : com.mchange.v2.c3p0.impl.NewProxyConnection@19dfb72a [wrapping: com.mysql.cj.jdbc.ConnectionImpl@17c68925]
7 : com.mchange.v2.c3p0.impl.NewProxyConnection@3d24753a [wrapping: com.mysql.cj.jdbc.ConnectionImpl@340f438e]
8 : com.mchange.v2.c3p0.impl.NewProxyConnection@7a0ac6e3 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@71be98f5]
9 : com.mchange.v2.c3p0.impl.NewProxyConnection@17f6480 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@2d6e8792]

Exception in thread "main" java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.

注意:

  • 配置文件里面配置的初始化创建的连接池对象是5个,最大连接池对象是8个。
  • 代码展示中一共创建了10个连接对象,但是只成功创建了9个连接对象,还剩一个出现超时异常(3秒左右)
  • 能够创建9个连接对象的原因是,我们归还了第五个连接池对象,这个连接池对象被第七个连接对象获取了,通过后面的哈希值可以判断出这两个连接池对象是同一个。
  • 最后一个连接对象没有创建成功的原因是,连接对象已经达到我们设定的最大连接数量 8个,如果没有归还的话,其他连接对象就不能被创建出来。


2.4 Druid 数据库连接池

  Apache Druid 是一个分布式内存实时分析系统,用于解决如何在大规模数据集下进行快速的、交互式的查询和分析。

  阿里云开元组件介绍——Druid


2.4.1 使用步骤

  1. 导入jar包

  2. 配置文件

    • 命名不固定。
    • 是 properties 形式的。
    • 可以放在任意路径下。
  3. 加载配置文件

    • 类:Properties
    • 方法:
      • getClassLoader()
      • getResourceAsStream()
      • load()
  4. 获取数据库连接池对象

    • 通过工厂类获取:DruidDataSourceFactory
  5. 获取连接

    • 获取方法:getConnection()

2.4.2 配置文件

  因为命名没有限制,这里取名为:druid.properties,内容如下:

# 数据库连接参数信息
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/demo_test?serverTimezone=UTC
username=root
password=root

# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000

2.4.3 Java代码基本演示:获取并打印连接对象

package com.base.datasource.druid;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * Druid连接池基本演示
 */
public class DruidDemo {
    public static void main(String[] args) throws Exception {
        //1. 加载配置文件,类加载器
        Properties pro = new Properties();
        InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
        pro.load(is);
        //2. 获取连接池对象
        DataSource ds = DruidDataSourceFactory.createDataSource(pro);
        //3. 获取连接对象
        Connection conn = ds.getConnection();
        //4. 打印连接对象
        System.out.println(conn);
    }
}

运行结果:

com.mysql.cj.jdbc.ConnectionImpl@62e136d3

2.4.4 Druid 工具类编写

  1. 编写工具类 JDBCUtils
package com.base.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtils {
    //1. 定义成员变量 DataSource
    private static DataSource ds;

    static {
        try {
            //1. 加载配置文件
            Properties pro = new Properties();
            pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            //2. 获取 DataSource
            ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接
     * @return Connection 对象
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    /**
     * 释放资源
     * @param stmt Statement对象
     * @param conn Connection对象
     */
    public static void close(Statement stmt, Connection conn) {

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 释放资源方法重载
     * @param rs ResultSet对象
     * @param stmt Statement 对象
     * @param conn Connection 对象
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取连接池对象
     * @return ds 连接池对象
     */
    public static DataSource getDataSource() {
        return ds;
    }
}
  1. 使用工具类创建连接,并执行简单数据库操作。
package com.base.datasource.druid;

import com.base.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 使用JDBC工具类
 * 完成添加操作,给account添加一条记录。
 */

public class DruidDemo2 {
    public static void main(String[] args) throws Exception {
     
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            //1. 获取连接
            conn = JDBCUtils.getConnection();
            //2. 定义 SQL
            String sql = "insert into account values(null,?,?)";
            //3. 获取 pstmt 对象
            pstmt = conn.prepareStatement(sql);
            //4. 给占位符(?)赋值
            pstmt.setString(1, "张三");
            pstmt.setDouble(2, 2000);
            //5. 执行 sql
            int count = pstmt.executeUpdate();
            System.out.println(count);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            JDBCUtils.close(pstmt, conn);
        }
    }
}

运行结果:

十月 31, 2019 4:24:03 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
1

注意:没有数据库和对应的表需要提前创建一个,下面提供SQL代码。

-- 创建数据库
CREATE DATABASE IF NOT EXISTS demo_test CHARACTER SET utf8 ;

USE demo_test;

CREATE TABLE account(
	id INT PRIMARY KEY AUTO_INCREMENT,
	name VARCHAR(32) UNIQUE NOT NULL,
	money VARCHAR(32) NOT NULL
);


时间:2019年10月31日15:59:13


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章