Day11-JDBC连接池&DBUtils

本文详细介绍了数据库连接池的原理和实现,包括自定义连接池和使用DBCP、C3P0两大常见连接池。同时,文章阐述了DBUtils在数据库操作中的应用,通过QueryRunner和ResultSetHandler简化了CRUD操作。

内容介绍

  • 使用DBCP,C3P0连接池完成基本数据库的操作
  • 使用DBUtils完成CRUD的操作

一,使用连接池DataSource 重写工具类


1.为什么使用连接池重写工具类

  • Connection对象在JDBC使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了.每次创建和销毁对象都是耗时操作.需要使用连接池对其进行优化.程序初始化的时候,初始化多个连接,将多个连接放入到池(集合)中.每次获取的时候,都可以直接从连接池中进行获取.使用结束以后,将连接归还到池中.
    耗费时间,耗费资源

2.连接池原理
- 目的:解决建立数据库连接耗费资源和时间很多的问题,提高性能。
这里写图片描述

3.编写连接池(自定义)
连接池中的主要方法:
1)生成指定数量的连接,写在静态代码块中
2)获取连接getConnection();
3)回收连接addBack();

3.1步骤
- 创建一个类,定义LinkedList集合作为连接池,在静态代码块中,向集合里面添加5个连接对象
使用LinkedList的原因:因为这个集合中有从头部取出removeFirst()和添加到尾部addLast()方法
- 添加addBack()方法,用作归还连接

  • 代码:
package com.itheima.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;

public class MyDataBase {
    static int connectionNum = 5;
    //用linkedList来存储连接,因为其中有从头取removeFirst()和添加回尾部addLast()方法,方便我们连接池操作;
    static LinkedList<Connection> pool = new LinkedList<>();
    //静态代码块,连接池中初始化连接
    static{
        for(int i=0;i<connectionNum;i++){
            try {
                Connection connection = new MyConnection(JDBCUTils.getConnection(),pool);
                pool.add(connection);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 从连接池中获取一个连接
     * 如果连接池中没有连接了就新创建一个连接
     * @return Connection
     * @throws SQLException
     */
    public Connection getConnection() throws SQLException{
        Connection connection = null;
        if(pool.size()>0){
            connection = pool.removeFirst();
        }else{
            connection = JDBCUTils.getConnection();
        }
        return connection;
    }

    //写完装饰后,这个函数直接没有用了
//    /**
//     * 回收连接
//     */
//    public void addBack(Connection connection){
//        pool.addLast(connection);
//    }

    /**
     * @return int连接池中连接的数量
     */
    public int getSize(){
        return pool.size();
    }
}

3.2编写连接池遇到的问题

  • 如果新建了connection,用完之后怎么判别是原池子中的connection(需要放回去),还是新建的connection(需要销毁)。

3.3解决办法(自定义一个Connection,重写close方法)

解决方法:装饰设计模式

继承

条件:可以控制父类的构造

装饰者模式
目的:改写已存在的类的某个方法或某些方法,装饰设计模式(包装模式)
条件:
1.包装类和被包装类实现的是同一个接口或者同一个父类;
2.包装类里面要拿到被包装类的引用
步骤:

  • 编写一个类实现一个接口,为被包装类
  • 编写一个类,实现与被包装类相同的接口。(具备相同的行为)
  • 定义一个被包装类类型的变量。
  • 定义构造方法,把被包装类类的对象注入,给被包装类变量赋值。
  • 对于不需要改写的方法,调用被包装类类原有的方法。
  • 对于需要改写的方法,写自己的代码。

通俗地讲,包装类中要定义一个被包装类对象,包装类的构造函数中传入被包装类的对象,并赋值给包装类中定义的那个被包装类对象,对于不需要改写的方法就直接调用该对象的正常方法即可,对于需要改写的方法就改写函数体就可以了。

3.4 datasource接口概述

  • Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商(用户)需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!
  • DataSource是遵循sun公司的那一套,连接的规范,真正的功能实现其实和我们自己写的自定义连接池MyConnectionPool差不多。里面常用的方法:getConnection();
    该DataSource接口的主要作用就是规范了自定义连接池中的函数的命名使之通用化。
  • 常见的连接池:DBCP、C3P0。

4.常用连接池

4.1 dbcp(Database Connection Pool )
这里写图片描述
4.1.1 dbcp概念

  • DBCP:Apache推出的Database Connection Pool
    核心API: 这是两个核心类
  • basicDatasource (一般是硬编码的时候使用)
  • basicDatasourceFactory (一般是导入配置文件的时候使用,使用的更多)
    需要结合properties类导入配置文件。
    BasicDataSourceFactory.CreateDataSource(Properties);//获得连接池

4.1.2 DBCP使用步骤

  • 添加jar包 commons-dbcp-1.4.jar commons-pool-1.5.6.jar(这两个jar包都需要导入)
  • 添加配置文件到src目录
  • 编写数据源工具类
//通过配置文件来写
public class DBCPUtils {
    static DataSource dataSource;
    static{
        Properties properties = new Properties();
        InputStream inputStream = DBCPUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
        try {
            properties.load(inputStream);
            dataSource = BasicDataSourceFactory.createDataSource(properties);
               //获得连接池
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得连接
     * @return
     * @throws Exception
     */
    public static Connection getConnection() throws Exception{
        return dataSource.getConnection();
    }

    /**
     * 释放资源
     * @param resultSet
     * @param statement
     * @param connection
     * @throws Exception
     */
    public static void realise(ResultSet resultSet, Statement statement, Connection connection) throws Exception {
        if (resultSet != null) {
            resultSet.close();
        }
        if (statement != null) {
            statement.close();
        }
        if (connection != null) {
            connection.close();
        }
    }
}
  • 通过硬编码来表写(不需要配置文件.了解一下)
DataSource basicDataSource = new BasicDataSource(); //直接new一个连接池basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); //设置配置basicDataSource.setUrl("jdbc:mysql://localhost:3306/day01_1");
basicDataSource.setUsername("root");basicDataSource.setPassword("123456");

4.2 c3p0

4.2.1 c3p0概念(这是我们最常用的连接池)
这里写图片描述
- C3P0开源免费的连接池!目前使用它的开源项目有:Spring、Hibernate等。使用第三方工具需要导入jar包,c3p0使用时还需要添加配置文件c3p0-config.xml
注意:c3p0的配置文件是以xml结尾的,而且文件名字不能改变;

4.2.2使用步骤

  • 添加jar包
  • 编写配置文件c3p0-config.xml,放在src中(注:文件名一定不要写错)
  • 配置完成后可以不像其他的常量池的一样需要加载这个文件,会自动读取的。但是一定要求文件名完全一致。
  • 注意配置文件中的命名,一定要符合函数中的命名,如果不知道这个规则,就用new ComboPooledDataSource()点出set函数,看set后面的命名是什么来命名,大小写都要一样。

  • 通过配置文件来编写

public class C3P0Utils  {

    static DataSource cpds;
    //静态代码块,加载的时候声明一个Datasource连接池
    static{
        cpds = new ComboPooledDataSource();
          //获得连接池;
    }

    /**
     * @return 返回一个连接池DataSource对象
     */
    public static DataSource getDataSource(){
        return cpds;
    }

    /**
     * @return 连接对象
     * @throws SQLException
     */
    public Connection getConnection() throws SQLException {
        return cpds.getConnection();
    }

    /**释放对象资源
     * @param resultSet
     * @param preparedStatement
     * @param connection
     * @throws SQLException
     */
    public void release(ResultSet resultSet,PreparedStatement preparedStatement,Connection connection) throws SQLException{
        if(resultSet != null){
            resultSet.close();
        }
        if(preparedStatement != null){
            preparedStatement.close();
        }
        if(connection !=null){
            connection.close();
        }
    }
}

c3po配置文件样板:
​ 可以在api(index(api).html)中去找:
打开后,7Configuration,最后一个Configuring Logging,点击后拉倒底就有。
样板:

<c3p0-config>
  <default-config>
    <property name="automaticTestTable">con_test</property>
    <property name="checkoutTimeout">30000</property>
    <property name="idleConnectionTestPeriod">30</property>
    <property name="initialPoolSize">10</property>
    <property name="maxIdleTime">30</property>
    <property name="maxPoolSize">100</property>
    <property name="minPoolSize">10</property>
    <property name="maxStatements">200</property>

    <property name="user">root</property>
    <property name="password">123456</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db_for_test</property>
    <property name="driverClass">com.mysql.jdbc.Driver</property>

  </default-config>
</c3p0-config>

这里写图片描述
- 通过硬编码来编写(不需要配置文件.了解一下),在api文档的快速开始里面可以直接复制过来

DataSource cpds = new ComboPooledDataSource(); cpds.setDriverClass("com.mysql.jdbc.Driver"); // loads the jdbc driver cpds.setJdbcUrl("jdbc:mysql://localhost:3306/day10");
cpds.setUser("root");
cpds.setPassword("123");

二,使用DBUtils 增删改查的操作

!!!DBUtils才是我们学习的第一个连接池框架。
1.案例分析
- 简化JDBC代码开发,本案例我们将采用apache commons组件一个成员:DBUtils。
- DBUtils就是JDBC的简化开发工具包。需要使用技术:连接池(获得连接)、SQL语句都没有少

2.案例相关知识

2.1javaBean组件
JavaBean就是一个类,在开发中常用于封装数据。具有如下特性
1.需要实现接口:java.io.Serializable ,通常偷懒省略了。
2.提供私有字段:private 类型 字段名;
3.提供getter/setter方法:
4.提供无参构造
这里写图片描述


3.DBUtils完成CRUD

3.1概述
- DBUtils是java编程中的数据库操作实用工具,小巧简单实用。 第一个操作数据库框架(jar),
- DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。
- Dbutils三个核心功能介绍
QueryRunner中提供对sql语句操作的API. update(), query()
ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

3.2QueryRunner核心类
- QueryRunner(DataSource ds) ,提供数据源(连接池),DBUtils底层自动维护连接connection
- update(String sql, Object… params) ,执行更新数据 insert update delete 参数就是一个数组,参数个数取决于语句中?的个数
- query(String sql, ResultSetHandler rsh, Object… params) ,执行查询 select

3.3ResultSetHandler结果集处理类
重点掌握三个:
BeanHandler:处理单条数据
BeanListHandler:处理多条数据;
ScalarHandler:处理单个数据,就是一行中的某一个字段。或者聚合数据返回的单个字段也可以使用。
ColumnHandler
这里写图片描述

3.4练习

public class MainTest {

     //查询符合条件的多行数据;
    @Test
    public void test01() throws SQLException{
        QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
        String sql = "select * from userinfo";
        Object[] params = {}; //不管有没有参数,都建议写上
        List<User> result = queryRunner.query(sql, new BeanListHandler<>(User.class), params);
        System.out.println(result);
    }

     //查询符合条件的单行数据
    @Test
    public void test02() throws SQLException{
        QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
        String sql = "select * from userinfo where id=?";
        Object[] params = {2};
        User result = queryRunner.query(sql, new BeanHandler<>(User.class), params);
        System.out.println(result);
    }

     //查询符合条件的单个数据
    @Test
    public void test03() throws SQLException{
        QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
        String sql = "select nickName from userinfo where id=?";
        Object[] params = {4};
        Object result = queryRunner.query(sql, new ScalarHandler(), params);
        System.out.println(result);
    }
}


      /**
       * 增加一条数据
       * @throws SQLException
       */
      @Test
      public void test01() throws SQLException{
           QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
           String sql = "insert into userinfo values(?,?,?,?,?)";
           Object[] params = {6,"光辉女郎","guanghui","法师","23"};
           int i = queryRunner.update(sql, params);
           System.out.println(i);
      }

      /**
       * 改变一条数据
       * @throws SQLException
       */
      @Test
      public void test05() throws SQLException{
           QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
           String sql = "update userinfo set nickName=? where username=?";
           Object[] params = {"长命老人","张三丰"};
           int i = queryRunner.update(sql, params);
           System.out.println("改变了"+i+"条数据");
      }

     //查询总行数,总记录数
      @Test
      public void test07() throws Exception{
           QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
           String sql = "select count(*) from userinfo";
           Object[] params = {};
           long result =(long) queryRunner.query(sql, new ScalarHandler(), params);
           System.out.println(result);
      }

     //查询指定的列
      @Test
      public void test07() throws Exception{
           QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
           String sql = "select * from userinfo";//这里是查询*,后面再取列
           Object[] params = {};
          List<Object> query
            = queryRunner.query(sql, new ColumnListHandler("name"), params);
           System.out.println(result);
      }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值