Java学习 day43_connectionPool&DBUtils

数据库连接池

1. 数据库连接池是什么

线程池:其实就是一个容器(池子)放了很多线程。因为我们每一次在使用线程的时候,都需要自己去创建一个线程,然后使用完了以后就把这个线程销毁了,这种做法明显是比较浪费资源的,而且效率也不高,所以我们利用这种池化的思想,把线程维护在一个线程池中,当我们需要使用线程的时候我们从线程池里面获取一个线程,然后执行任务,这个线程使用完了之后不会去销毁,而是放到线程池中。

我们的数据库连接池也是一样的,在一个数据库连接池中,维护很多个数据库连接(具体来说就是Connection),当我们需要使用数据库连接的时候,我们从数据库连接池里面去获取一个数据库连接,然后用他处理SQL请求,当我们使用完了这个连接以后,再把这个连接对象返回数据库连接池。

在这里插入图片描述

2. 自己手动实现一个数据库连接池

package com.cskaoyan.connection;

import com.cskaoyan.utils.JDBCUtils;

import java.sql.Connection;
import java.util.LinkedList;

// 自己去写一个数据库连接池
public class MyConnectionPool {

    // 一个装 connection对象的链表
    // 从头部取,从尾部存
    static LinkedList<Connection> connectionPools;

    // 初始大小
    final static int INIT_SIZE = 10;

    // 临界大小
    final static int MIN_SIZE = 5;

    // 每次扩容的大小
    final static int ADD_SIZE = 10;

    static {

        connectionPools = new LinkedList<>();

        addCapcity(INIT_SIZE);

    }

    // 获取连接
    public static Connection getConnection(){

        // 自动扩容
        if (connectionPools.size() < MIN_SIZE) {
            addCapcity(ADD_SIZE);
        }

        Connection connection = connectionPools.removeFirst();

        return connection;

    }

    // 扩容方法
    private static void addCapcity(int size) {
        if (size < 1) {
            return;
        }
        for (int i = 0; i < size; i++) {
            Connection connection = JDBCUtils.getConnection();
            connectionPools.addLast(connection);
        }

    }


    // 回收连接
    public static void recyleConnection(Connection connection) {

        connectionPools.addLast(connection);

    }

}

还需要优化的地方:

  1. 可以把一些静态的成员变量写到配置文件中,通过配置文件来设置,会更加灵活

  2. 连接池里面的连接会不断增多,但是增多之后没有一个超时自动回收的机制

  3. 我们没有给连接池里面的连接数量定义上限

  4. 我们自己实现的数据库连接池需要实现javax.sql.Datasource这个接口

    这个接口主要的目的其实就是给我们定义好 获取连接的方法


那为什么Datasource这个接口没有定义回收连接的方法呢?
用户用完了连接池当中的连接,有可能会自己先关闭再放回连接池当中,返回给连接池的就只是一个被关闭的连接

在这里插入图片描述



3. 使用第三方开源的数据库连接池

3.1 DBCP

是Apache下面的一个开源项目,是一个比较老的开源的数据库连接池。目前在公司里面的新项目中,基本不会使用它

  • 导包

    在这里插入图片描述

  • 配置

    #连接设置
    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/33th
    username=root
    password=123456
    
    #<!-- 初始化连接 -->
    initialSize=10
    
    #最大连接数量
    maxActive=20
    
    #<!-- 最大空闲连接 -->
    maxIdle=20
    
    #<!-- 最小空闲连接 -->
    minIdle=5
    
    #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
    maxWait=60000
    
    
    #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
    #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
    connectionProperties=useUnicode=true;characterEncoding=utf8;useSSL=false;serverTimezone=Aisa/Shanghai
    
    #指定由连接池所创建的连接的自动提交(auto-commit)状态。
    defaultAutoCommit=true
    
    #driver default 指定由连接池所创建的连接的只读(read-only)状态。
    #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
    defaultReadOnly=
    
    #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
    #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
    defaultTransactionIsolation=REPEATABLE_READ
    # set global/session transaction isolation level read uncommitted
    
  • 使用

    package com.cskaoyan.utils;
    
    import org.apache.commons.dbcp.BasicDataSourceFactory;
    
    import javax.sql.DataSource;
    import java.io.FileInputStream;
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.Properties;
    
    public class DBCPUtils {
    
        // 声明一个数据库连接池(接口)
        static DataSource dataSource;
    
        static {
    
            try {
                Properties properties = new Properties();
                // 读取配置文件
                FileInputStream fileInputStream = new FileInputStream("dbcp.properties");
                properties.load(fileInputStream);
    
                dataSource = BasicDataSourceFactory.createDataSource(properties);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        // 获取连接
        public static Connection getConnection(){
    
            Connection connection = null;
            try {
                connection = dataSource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return connection;
        }
    }
    

3.2 C3P0

  • 导包

    在这里插入图片描述

  • 配置

    我们使用C3p0数据库连接池,需要在src目录下配置一个名字叫做 c3p0-config.xml 的文件,文件里位置不能改变,文件的名字也不能改变

    <?xml version="1.0" encoding="UTF-8"?>
    <c3p0-config>
        <default-config>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <!--
            在xml文件里面,有一些特殊字符,需要写他的转义字符
    
            >    &gt;
            <    &lt;
            &    &amp;
    
            >=   &gt;=
            -->
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/33th?useSSL=false&amp;characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai</property>
            <property name="user">root</property>
            <property name="password">123456</property>
    
            <property name="acquireIncrement">5</property>
            <property name="initialPoolSize">10</property>
            <property name="minPoolSize">5</property>
            <property name="maxPoolSize">20</property>
        </default-config>
    </c3p0-config>
    
  • 使用

    package com.cskaoyan.utils;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    
    public class C3p0Utils {
    
        // 数据库连接池对象
        private static DataSource dataSource;
    
        static {
    
            dataSource = new ComboPooledDataSource();
    
        }
    
    
        public static Connection getConnection(){
            
    		// 注意:这里返回的对象不是一个JDBC4Connection对象
            Connection connection = null;
            try {
                connection = dataSource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
    
            return connection;
    
        }
    }
    

3.3 Druid

这个是阿里巴巴开源的一个数据库连接池,以性能强大,稳定,还带有性能监控功能而风靡。目前是有apache来维护。

  • 导包

    在这里插入图片描述

  • 配置

    这个数据库连接池的配置和我们DBCP是有点类似的,都是通过properties配置文件来配置

    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/33th?useSSL=false&characterEncoding=utf8
    username=root
    password=123456
    
  • 使用

    package com.cskaoyan.utils;
    
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    import javax.sql.DataSource;
    import java.io.FileInputStream;
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.Properties;
    
    public class DruidUtils {
    
        private static DataSource dataSource;
    
        static {
            try {
    
                // 加载配置文件
                Properties properties = new Properties();
                FileInputStream fileInputStream = new FileInputStream("druid.properties");
    
                properties.load(fileInputStream);
    
                // 通过配置文件里面的配置,来创建数据库连接池
                dataSource = DruidDataSourceFactory.createDataSource(properties);
            }catch (Exception ex) {
                System.out.println("初始化数据库连接池失败...");
                ex.printStackTrace();
            }
    
        }
    
        // 获取连接的方法
        public static Connection getConnection(){
    
            Connection connection = null;
            try {
                connection = dataSource.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
    
            return connection;
    
        }
    }
    

DBUtils

1. 介绍

DBUtils是一个对我们JDBC的公共操作做了一个简单封装的框架或者是叫做工具类库。

DBUtils 有三个核心的组件:
QueryRunner:该类提供了 DML 和 DQL 的 API。
ResultSetHandler:该接口定义如何封装结果集。
DbUtils:一个简单的工具类,简化了关闭资源和事务处理,可以简化JDBC操作的模板代码。

框架是什么呢?

框架就是一个半成品的软件。这个半成品的软件有一些基础的功能,但是不能作为一个软件独立运行。我们去使用框架其实是在框架的基础之上进行二次开发,开发出适合我们业务需求的产品(软件)。框架就好比毛坯房,不能住人,我们的产品就是精装修房,可以住人。

DBUtils的功能比较简单,里面提供了很多可以方便我们进行JDBC操作的一个API,这些API的出现,简化了我们使用JDBC编程的代码量。

2. 使用

		// 获取连接
 		Connection connection = JDBCUtils.getConnection();

        // 获取statement对象
        // 这个statement对象是用来去封装sql语句,使sql语句变成一个网络请求,然后发送给MySQL服务器
        Statement statement = connection.createStatement();

        // 发送SQL请求
        ResultSet resultSet = statement.executeQuery("select id,name,p_id from city");
        // 获取结果集、解析结果集
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            int pId = resultSet.getInt("p_id");

            System.out.println("id:" + id);
            System.out.println("name:" + name);
            System.out.println("pId:" + pId);
        }

        // 关闭资源
        JDBCUtils.closeSources(connection,statement,resultSet);

DBUtils这个工具类库其实就是可以帮助我们更加简单的去执行SQL语句,更加方便的去解析结果集

  • 导包

    在这里插入图片描述

  • 配置

    DBUtils不需要额外的配置

  • 使用

    具体而言就是使用以下的三个类 来简单我们的JDBC的操作

2.1 DbUtils

我们发现,这个DBUtils这个类里面其实就是封装了一些简单的方法,帮助我们去关闭资源、提交事务、回滚事务等等。

大多数情况下,我们都不使用DBUtils这个类,这个类基本没什么用。

在这里插入图片描述

2.2 QueryRunner

这个类是帮助我们去执行SQL语句的。

// 构造方法
QueryRunner queryRunner = new  QueryRunner();

QueryRunner queryRunner = new  QueryRunner(Datasource datasource);

// 执行sql
queryRunner.update(String sql);
queryRunner.update(Connection conn, String sql);

queryRunner.update(String sql,Object param);
queryRunner.update(Connection conn, String sql,Object param);

queryRunner.update(String sql,Object... param);
queryRunner.update(Connection conn, String sql,Object... param);

// 到底选择哪一个API呢?
// 首先我们需要根据QueryRunner的构造方法,看一下我们去创建QueryRUnner的时候是否传入了数据库连接池
// 如果传入了数据库连接池,那么在后续使用API的时候,就可以不传入connection对象
// 如果我们去创建QueryRUnner对象的时候,使用的是无参构造方法,那么我们在执行sql的时候一定要传入connection对象

// 查询的API
queryRunner.query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params)
queryRunner.query(String sql, ResultSetHandler<T> rsh, Object... params)
    
queryRunner.query(Connection conn, String sql, ResultSetHandler<T> rsh)
queryRunner.query(String sql, ResultSetHandler<T> rsh)

update:

public class DButilsUpdateMain {


    public static void main(String[] args) throws SQLException {

        // 获取连接
        Connection connection = DruidUtils.getConnection();


        // 创建一个QueryRunner对象
        QueryRunner queryRunner = new QueryRunner();


        // 执行SQL语句
        String sql = "update student set name = ? where id = ?";
		
		// 返回的是影响的行数
        int affectedRows = queryRunner.update(connection,sql,"段誉",10);

        System.out.println("affectedRows:" + affectedRows);
        // 解析结果集

        // 关闭资源
        connection.close();

    }

}

2.3 ResultSetHandler

其实这个类就是一个结果集处理器。可以帮助我们把SQL语句查询的结果集对象(ResultSet)封装成Java对象

底层原理:反射
如果我们要使用ResultSetHandler接收结果,比如结果要封装为一个Student对象,一定要给Student类写好get/set方法,因为ResultSetHandler是通过反射来把结果封装成对象的。
我就是因为写错了set的名字,导致接收到的日期值一直是null,一开始没有认为是set的问题,因为并没有调用过set

在这里插入图片描述


2.3.1 BeanHandler

将结果集中的第一行数据封装到一个对应的JavaBean实例中。

public class BeanHandlerDemo {

    // 实践一下BeanHandler
    public static void main(String[] args) throws SQLException {

        // 创建一个QueryRunner对象
        QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());

        // 执行SQL语句
        Student student = queryRunner.query("select id,name,chinese,english,math,birthday,native_place as nativePlace from student where id = ?",new BeanHandler<>(Student.class),4);

        System.out.println(student);

    }


}

2.3.2 BeanListHandler

将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。


// 这个Handler其实是把resultSet里面的每一行都转化为一个Java对象,最后给我们返回一个Java对象的集合
public class BeanListHandlerDemo {

    public static void main(String[] args) throws SQLException {

        // 创建QUeryRunner
        QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());

        // 执行sql
        List<Student> studentList = queryRunner.query("select id,name,chinese,english,math,birthday,native_place as nativePlace from student", new BeanListHandler<Student>(Student.class));


        // 输出
        System.out.println(studentList);
    }
}

2.3.3 ColumnListHandler

将结果集中某一列的数据存放到List中


// 把单列的值封装到一个list里面去
public class ColumnListHandlerDemo {

    public static void main(String[] args) throws SQLException {

        // 创建QueryRUnner对象
        QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());

        // 执行sql
        List<String> nameList = queryRunner.query("select name from student", new ColumnListHandler<>());

        System.out.println("nameList:" + nameList);

    }
}

2.3.4 ScalarHandler

将单个值封装,可以用来统计聚合函数count(),max(),min(),avg()等方法返回的值

// 获取单个值
public class ScalarHandlerDemo {

    public static void main(String[] args) throws SQLException {


        // 创建QUeryRUnner
        QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());

        Long count = queryRunner.query("select count(id) from user", new ScalarHandler<>());

        System.out.println("count:" + count);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值