飞道的博客

Java_16_JDBC&连接池:连接池(c3p0连接池、druid连接池)

569人阅读  评论(0)

一、连接池

连接池和线程池类似,连接池是一个用来创建和管理连接对象的容器,使用连接池可以让数据库的连接复用

回顾连接池
线程池是一个负责创建线程和管理线程的容器,使用线程池可以节省资源开销。

常用的连接池

C3P0连接池
DRUID连接池

二、C3P0连接池

C3PO是一个开源的连接池。Hibernate框架默认推荐使用C3PO作为连接池实现。
C3PO地址: https://sourceforge.net/projects/c3p0/?source-navbar
C3PO的jar包: c3pe-0.9.1.2.jar

1、C3P0配置文件

要使用C3PO连接池,需要设置一些参数。使用配置文件设置参数是最方便的方法,我们通过使用配置文件方式去设置C3P0参数。

配置文件的要求:
1、文件名: c3p0-config.xml
2、放在源代码即src目录下
3、配置方式一:使用默认配置(default-config)
4、配置方式二:使用命名配置(named-config)

C3P0配置文件名称必须为c3p0-config.xml,文件里面的命名配置(named-config)可以有多个

C3P0配置文件示例

<c3p0-config>
  <!-- 使⽤用默认的配置读取连接池对象 -->
  <default-config>
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">10</property>
    <property name="checkoutTimeout">2000</property>
    <property name="maxIdleTime">1000</property>
  </default-config>

  <!-- 使⽤用命名的配置读取连接池对象 -->
  <named-config name="itheimac3p0"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">15</property>
    <property name="checkoutTimeout">2000</property>
    <property name="maxIdleTime">1000</property>
  </named-config>
</c3p0-config>

C3PO参数说明

数据库连接参数(必须项)

driverClass:驱动类全名
jdbcUrl:连接字符串
user:用户名
password:密码

常用的连接池配置参数:


初始连接数:刚创建好连接池的时候准备的连接数量
最大连接数:连接池中最多可以放多少个连接
最大等待时间:连接池中没有连接时最长等待时间
最大空闲回收时间:连接池中的空闲连接多久没有使用就会回收

完整参数表

2、C3P0连接池对象(ComboPooledDatasource类)

com. mchange.v2. c3pe. ComboPooledDatasource类表示C3PO的连接池对象。
常用2种创建连接池的方式:
1、无参构造,使用默认配置
2、有参构造,使用命名配置

ComboPooledDatasource类构造方法

//无参构造使用默认配置(使用xml中default-config标签中对应的参数)
public ComboPooledDataSource()

//有参构造使用命名配置(configName: xml中配置的名称,使用xml中named-config标签中对应的参数)
public ComboPooledDataSource(String configName)

ComboPooledDatasource类对象方法

//从连接池中取出一个连接
public Connection getConnection() throws SQLException

3、C3P0连接池的使用步骤

1、导入jar包

2、准备配置文件
文件名:必须是c3p0-config.xml
文件位置:必须在src目录下
配置方式一:使用默认配置(default-config)
配置方式二:使用命名配置(named-config)

3、在配置文件中编写配置信息
数据库连接参数
url:连接字符串
driverClass:驱动类全名
user:用户名
password:密码

连接池参数
初始化连接数:连接池中一开始创建指定数量的连接对象 5
最大连接数:连接池中可以存储的连接对象最大数量 10
最大等待时间:当连接池中没有连接对象可用时需要等多长时间,当指定时间内没有连接可以则直接抛出异常。
最大空闲时间:2000

4、创建连接池对象

5、调用连接池对象的getConnection方法获得连接对象并操作数据库

6、调用连接对象的close方法将连接对象放回池中等待复用。

4、C3P0连接池使用示例1

在src下,创建C3P0配置文件模板:c3p0-config.xml

<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  数据库连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">10</property>
    <property name="checkoutTimeout">2000</property>
    <property name="maxIdleTime">1000</property>
  </default-config>

  <!-- 使用命名的配置读取连接池对象 --> 
  <named-config name="itheimac3p0"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">15</property>
    <property name="checkoutTimeout">2000</property>
    <property name="maxIdleTime">1000</property>
  </named-config>
</c3p0-config>

使用c3p0连接池

package com.itheima._10C3P0连接池;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.sql.Connection;

/**
    目标:创建C3P0连接池并从池中获得连接对象
 */
public class C3P0Demo01 {
    public static void main(String[] args)throws Exception {
        // 创建连接池对象:使用默认配置
        // ComboPooledDataSource ds = new ComboPooledDataSource();
        // 创建连接池对象:使用命名配置
        ComboPooledDataSource ds = new ComboPooledDataSource("itheimac3p0");
        for (int i = 0; i < 16; i++) {
            // 从连接池中获得连接对象
            Connection conn = ds.getConnection();
            System.out.println(i+"="+conn);

            if (i == 5) {
                // 关闭连接:并不是直接关闭了而是将连接对象放回池中等待复用
                // invoke
                conn.close();
            }
        }
    }
}

案例效果
正常获取连接池中连接

获取连接池中连接超时

5、C3P0连接池使用示例2

准备数据

CREATE TABLE student (
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20),
	age INT,
	score DOUBLE DEFAULT 0.0
)

配置文件

<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  数据库连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">10</property>
    <property name="checkoutTimeout">2000</property>
    <property name="maxIdleTime">1000</property>
  </default-config>

  <!-- 使用命名的配置读取连接池对象 --> 
  <named-config name="itheimac3p0"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/day25</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">15</property>
    <property name="checkoutTimeout">2000</property>
    <property name="maxIdleTime">1000</property>
  </named-config>
</c3p0-config>

java代码

 public class Demo01 {

     public static void main(String[] args) throws Exception {
         // 方式一: 使用默认配置(default-config)
         // new ComboPooledDataSource();
 //    ComboPooledDataSource ds = new ComboPooledDataSource();

         // 方式二: 使用命名配置(named-config:配置名)
         // new ComboPooledDataSource("配置名");
         ComboPooledDataSource ds = new ComboPooledDataSource("otherc3p0");

 //   for (int i = 0; i < 10; i++) {
 //     Connection conn = ds.getConnection();
 //     System.out.println(conn);
 //   }

         // 从连接池中取出连接
         Connection conn = ds.getConnection();

         // 执行SQL语句
         String sql = "INSERT INTO student VALUES (NULL, ?, ?, ?);";
         PreparedStatement pstmt = conn.prepareStatement(sql);
         pstmt.setString(1, "张三");
         pstmt.setInt(2, 25);
         pstmt.setDouble(3, 99.5);

         int i = pstmt.executeUpdate();
         System.out.println("影响的行数: " + i);
         pstmt.close();
         conn.close(); // 将连接还回连接池中
     }
 }

案例效果
使⽤用连接池中的连接往数据库添加数据

总结

配置文件名称必须为:c3pe-config.xml ,将配置文件放在src目录下。使用配置文件方式好处:只需要单独修改配置文件,不用修改代码。
多个命名配置的好处:
1、可以连接不同的数据库: db1,db2。
2、可以使用不同的连接池参数: maxPoolSize
3、可以连接不同厂商的数据库: Oracle或MySQL

三、DRUID连接池

Druid是阿里巴巴开发的号称为监控而生的数据库连接池,,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。
Druid地址: https://github.com/alibaba/druid
DRUID连接池使用的jar包: druid-1.0.9.jardruid-1.0.9.jar

为什么使用DRUID连接池
c3p0连接池有点慢,所以使用更好的druid连接池

1、DRUID配置文件

DRUID连接池在创建的时候需要一个Properties对象来设置参数,所以我们使用properties文件来保存对应的参数。DRUID连接池的配置文件名称随便,建议放到src目录下面方便加载。

DRUID配置文件示例

创建properties文件,命名为druid.properties(随意命名)文件内容:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/day25
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3

DRUID常用参数说明

2、DRUID连接池对象(DruidDatasourceFactory类)

com.alibaba.druid.pool.DruidDatasourceFactory类有创建连接池的方法

public static DataSource createDataSource (Properties properties)
//创建一个连接池,连接池的参数使用properties中的数据

3、DRUID连接池的使用步骤

1、在src目录下创建一个properties文件,并设置对应参数
2、加载properties文件的内容到Properties对象中
3、创建DRUID连接池,使用配置文件中的参数
4、从DRUID连接池中取出连接
5、执行SQL语句
6、关闭资源

4、DRUID连接池使用示例1

在src目录下新建一个DRUID配置文件,命名为: druid.properties,内容如下

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/day25
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3

java代码

/**
    目标:创建Druid连接池并从池中获得连接对象
    使用步骤:
        1. 导入相关jar
        2. 准备配置文件
            * 文件名任意:一般是druid.properties
            * 文件位置:可以存储在任意目录下,一般存储在src目录下
        3. 编写配置信息
            * 数据库连接参数:连接字符串,驱动类全名,用户名,密码
            * 连接池参数:初始连接数,最大连接数,最大等待时间
        4. 创建druid连接池对象
            * 通过工具类DruidDataSourceFactory方法创建
        5. 调用连接池对象的getConnection获得连接对象操作数据
        6. 调用连接对象的close方法关闭连接:不是真正关闭而是放回池中
 */
public class DruidDemo01 {
    public static void main(String[] args) throws Exception{
        // 4. 创建druid连接池对象 
        // 4.1 创建属性集对象
        Properties info = new Properties();
        // 4.2 加载配置信息到集合中
        info.load(DruidDemo01.class.getResourceAsStream("/druid.properties"));
        DataSource ds = DruidDataSourceFactory.createDataSource(info);
        // 5. 调用连接池对象的getConnection获得连接对象
        for (int i = 0; i < 11; i++) {
            Connection conn = ds.getConnection();
            if (i == 5) {
                // 6. 调用连接对象的close方法关闭连接:不是真正关闭而是放回池中
                conn.close();
            }
        }
    }
}

案例效果
正常获取连接池中的连接

获取连接池中的连接超时

5、DRUID连接池使用示例2

java代码

public class Demo02 {
  public static void main(String[] args) throws Exception {
    // 加载配置文件中的配置参数
    InputStream is = Demo03.class.getResourceAsStream("/druid.properties");
    Properties pp = new Properties();
    pp.load(is);
    
    // 创建连接池,使用配置文件中的参数
    DataSource ds = DruidDataSourceFactory.createDataSource(pp);
    
//    for (int i = 0; i < 10; i++) {
//      Connection conn = ds.getConnection(); //      System.out.println(conn);
//    }
    
    // 从连接池中取出连接
    Connection conn = ds.getConnection();
    
    // 执行SQL语句
    String sql = "INSERT INTO student VALUES (NULL, ?, ?, ?);";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setString(1, "王五");
    pstmt.setInt(2, 35);
    pstmt.setDouble(3, 88.5);
    
    int i = pstmt.executeUpdate();
    System.out.println("影响的行数: " + i);
    // 执行查询
    sql = "SELECT * FROM student;";
    ResultSet rs = pstmt.executeQuery(sql);
    
    while (rs.next()) {
      int id = rs.getInt("id");
      String name = rs.getString("name");
      int age = rs.getInt("age");
      double score = rs.getDouble("score");
      System.out.println("id: " + id + " ,name: " + name + " ,age = " + age + " ,score = " + score);
    }
    
    pstmt.close();
    conn.close(); // 将连接还回连接池中
  }
}

案例效果
使用DRUID连接池中的连接操作数据库

总结

DRUID连接池根据Properties对象中的数据作为连接池参数去创建连接池,我们自己定义properties类型的配置文件,名称自己取,也可以放到其他路径,建议放到src目录下方便加载。
不管是C3PO连接池,还是DRUID连接池,配置大致都可以分为2种:1、连接数据库的参数
2、连接池的参数,这2种配置大致参数作用都相同,只是参数名称可能不一样。

四、DRUID连接池工具类

我们每次操作数据库都需要创建连接池,获取连接,关闭资源,都是重复的代码。我们可以将创建连接池和获取连接池的代码放到一个工具类中,简化代码。

工具类步骤:
1、声明静态数据源成员变量
2、创建连接池对象
3、定义公有的得到数据源的方法
4、定义得到连接对象的方法
5、定义关闭资源的方法

使用连接池工具类后可以简化代码,我们只需要写SQL去执行。

DRUID连接池工具类代码

DataSourceUtils.java

/**
 * 数据源工具类
 *
 * 数据源工具类实现步骤
 * 1)	创建私有静态数据源成员变量 DataSource ds
 * 2)	在静态代码块中创建连接池
 * 	a)	创建属性集对象
 * 	b)	从类路径下加载属性文件,得到输入流对象
 * 	c)	通过工厂类创建一个数据源
 * 3)	创建公有的得到数据源的方法 getDataSource()
 * 4)	创建得到连接对象的方法 getConnection()
 * 5)	创建释放资源的方法 close(Connction conn, Statement stmt, ResultSet rs)
 */
public class DataSourceUtils {
    // 1)	创建私有静态数据源成员变量 DataSource ds
    private static DataSource ds = null;

    // 2)	在静态代码块中创建连接池
    static {
       try{
           Properties info = new Properties();
           // 4.2 加载配置信息到集合中
           info.load(DruidDemo01.class.getResourceAsStream("/druid.properties"));
           ds = DruidDataSourceFactory.createDataSource(info);
       } catch(Exception e){
           e.printStackTrace();
       }
    }

    // 3)	创建公有的得到数据源的方法 getDataSource()
    public static DataSource getDataSource(){
        return ds;
    }

    // 4)	创建得到连接对象的方法 getConnection()
    public static Connection getConnection(){
        try {
            return ds.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //  5. 定义关闭资源的方法:close(Connection conn, Statement stmt, ResultSet rs)
    public static void close(Connection conn, Statement stmt, ResultSet rs){
        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();
            }
        }
    }

    //  重载关闭方法:close(Connection conn, Statement stmt)
    public static void close(Connection conn, Statement stmt){
        close(conn, stmt, null);
    }
}

测试连接池工具类

使用数据源工具类获得连接对象并执行数据库操作。

/**
 * 数据源工具类测试
 */
public class DataSourceUtilsDemo01 {
    public static void main(String[] args)throws Exception {
        // 1. 获得连接对象
        Connection conn = DataSourceUtils.getConnection();
        // 2. 获得预编译对象
        PreparedStatement ps = conn.prepareStatement("delete from student where id = ?;");
        // 3. 给占位符赋值
        ps.setInt(1, 5);
        // 4. 执行SQL,返回影响的行数
        int row = ps.executeUpdate();
        System.out.println(row);
        // 5. 关闭资源
        DataSourceUtils.close(conn, ps);
    }
}

小结

数据源工具类实现步骤

  1. 创建私有静态数据源成员变量 DataSource ds
  2. 在静态代码块中创建连接池
    a) 创建属性集对象
    b) 从类路径下加载属性文件,得到输入流对象
    c) 通过工厂类创建一个数据源
  3. 创建公有的得到数据源的方法 getDataSource()
  4. 创建得到连接对象的方法 getConnection()
  5. 创建释放资源的方法 close(Connction conn, Statement stmt, ResultSet rs)

五、连接池硬编码方式(了解)

硬编码方式实现连接池仅作了解即可。硬编码即参数都写死在源码中
使用纯代码获取配置连接池最大的弊端是:所有配置信息都写在代码中。一旦需要改配置信息,就需要改动源代码,非常麻烦。

准备数据

CREATE TABLE student (
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(20),
  age INT,
  score DOUBLE DEFAULT 0.0 );

硬编码方式实现C3P0连接池

public class Demo01 {

  public static void main(String[] args) throws Exception {
    // 2.创建连接池对象ComboPooledDataSource对象
    ComboPooledDataSource ds = new ComboPooledDataSource();
    
    // 连接到数据库的相关参数
    // 3.设置连接参数:driverClass , jdbcUrl, user, password
    ds.setDriverClass("com.mysql.jdbc.Driver"); // 设置驱动的名称
    ds.setJdbcUrl("jdbc:mysql://localhost:3306/day25");
    ds.setUser("root");
    ds.setPassword("root");
    
    // 4.设置连接池参数
    // a.初始连接数initialPoolSize
    ds.setInitialPoolSize(5);
    
    // b.最大连接数maxPoolSize
    ds.setMaxPoolSize(10);
    
    // c.最大等待时间checkoutTimeout
    // Java程序去连接池中取连接,最长的等待时间,超过这个时间会有异常
    ds.setCheckoutTimeout(5000);
    
    // d.最大空闲回收时间maxIdleTime
    // 连接池中的连接超过这个时间没有人使用,就会自动销毁
    ds.setMaxIdleTime(3000);
    
    Connection conn = ds.getConnection(); // 从一个连接池中取出一个连接
    String sql = "INSERT INTO student VALUES (NULL, ?, ?, ?);";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setString(1, "张三");
    pstmt.setInt(2, 25);
    pstmt.setDouble(3, 99.5);
    
    int i = pstmt.executeUpdate();
    System.out.println("INSERT 影响的⾏行行数:" + i);
    pstmt.close();
    conn.close(); // 将连接还回连接池中
  }
}

硬编码方式实现DRUID连接池

public class Demo02 {
  public static void main(String[] args) throws Exception {
    DruidDataSource ds = new DruidDataSource();
    // 设置连接参数
    ds.setDriverClassName("com.mysql.jdbc.Driver");
    ds.setUrl("jdbc:mysql://127.0.0.1:3306/day25");
    ds.setUsername("root");
    ds.setPassword("root");
    
    // 设置连接池参数
    ds.setInitialSize(5);
    ds.setMaxActive(10);
    ds.setMaxWait(3000);
    ds.setMinIdle(3);
    
    // 从连接池中取出连接
    Connection conn = ds.getConnection();
    
    // 执行SQL语句
    String sql = "INSERT INTO student VALUES (NULL, ?, ?, ?);";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setString(1, "王五");
    pstmt.setInt(2, 35);
    pstmt.setDouble(3, 88.5);
    
    int i = pstmt.executeUpdate();
    System.out.println("影响的行数: " + i);
    
    pstmt.close();
    conn.close(); // 将连接还回连接池中
  }
}

转载:https://blog.csdn.net/qq_45942076/article/details/105832072
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场