数据库连接池(常用的德鲁伊)

大家好,我是一名入门的菜鸟,如果你不经意间翻开了我的文章,谢谢您,您的支持是我前进的动力,让我们一起加油!!
由于不是名牌大学,只是一个普普通通的专科生,所以,我想通过自己的努力来获得我想要的,我不会放弃我的梦想,我也曾幻想着我成功的时候在朋友边吹嘘,也曾想象到我失败时候潦倒的样子,幻想始终是幻想,我会努力的,加油,你一定能行


1 连接池概述

  • 连接对象的使用问题
    我们原先连接数据库都是用一次创建连接一次,不用的话就直接关闭了,然后在使用在创建,这样就造成了占用资源过多加重服务器负担,耗时。
  • 解决
    解决这些问题,我们要考虑如何提高连接速度,还有就是如何提高使用率。

下面会详细介绍一种最实用的数据库连接池的详细介绍及其使用------德鲁伊(druid)


经过上面的介绍,我们需要创建一个连接池,以供我们连接数据库操作,在没用连接池之前,用户访问数据库的时候都是自己创建连接对象的。
在这里插入图片描述

我们使用了连接池之后:从系统开始启动的时候就会创建一个工厂对象,里面有一定数量的数据库连接对象,用户使用的时候直接会从池子里拿连接对象,不需要自己在创建了。
在这里插入图片描述

连接池解决现状问题的原理

Connection连接对象操作特点
创建时连接对象不再由自己创建,而是系统启动的时候已经创建一定数量的连接,
并且放在连接池中
使用时直接从连接池中去获取一个已经创建好的连接对象即可
关闭时不是真的关闭连接对象,而是将连接对象再放回到连接池中,供下一个用户使用
  1. 数据源接口:javax.sql.DataSource接口

数据源接口中的方法:

DataSource接口中的方法描述
Connection getConnection()从连接池中获取连接对象

每个连接池都会有很多的参数,每个参数都有不同的含义,几乎所有的参数都是由默认值的,参数名在不同的连接池中代表的意思也有所差异!

常用参数描述
初始连接数服务器启动的时候创建的连接对象数量
最大连接数连接池中最多可以允许放多少个连接对象
最长等待时间如果连接池中没有连接对象,设置用户等待的最长时间是多久,单位是毫秒。
如果超过这个时间就抛出异常
最长空闲回收时间如果一个连接对象长时间没有人使用,设置多久回收这个对象,默认是不回收。

2 常用的连接池(我们首选druid)

常用连接池的介绍

DataSource本身是Oracle公司提供的一个接口,本身没有具体的实现,它的实现由各大连接池的数据库厂商去实现,我们只需要学习如何使用就ok了。

常用的连接池组件:

  1. 阿里巴巴-德鲁伊druid连接池:Druid是阿里巴巴开源平台上的一个项目(主要)。
  2. DBCP(DataBase Connection Pool)数据库连接池,是Apache上的一个Java连接池项目,也是Tomcat使用的连接池组件。
  3. C3P0是一个开源的JDBC连接池,目前使用它的开源项目有Hibernate,Spring等。C3P0有自动回收空闲连接功能。

使用Druid连接池

DRUID简介

Druid是阿里巴巴开发的号称为监控而生的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。如:一年一度的双十一活动,每年春运的抢火车票。

Druid的下载地址:https://github.com/alibaba/druid

DRUID连接池使用的jar包:druid-1.0.9.jar

常用的配置参数

参数说明
url连接字符串
username用户名
password密码
driverClassName驱动类名,会自动根据URL识别,这一项可以不配置
initialSize初始连接数
maxActive最大连接数
maxWait最长等待时间

Druid连接池API介绍

  1. 得到配置文件的输入流
Class类中的方法说明
InputStream getResourceAsStream(String path)加载类路径下配置文件,转成一个输入流对象
  1. Properties类的方法,读取属性文件中的键和值,并且加载到集合中
    在这里插入图片描述
  2. 通过Druid工厂的静态方法创建连接池,提供属性集合作为参数
DruidDataSourceFactory的方法方法
public static DataSource createDataSource(Properties properties)通过属性集合中属性,创建一个连接池

3 使用Druid连接池

案例演示:获取连接对象

导包:
在这里插入图片描述

步骤

  1. 在src目录下创建一个properties文件,文件名随意,设置上面的参数
  2. Java代码
    1. 加载properties文件的内容到Properties对象中
    2. 使用工厂类,创建DRUID连接池,使用配置文件中的参数
    3. 从DRUID连接池中取出10个连接输出

在这里插入图片描述

.properties配置文件:

url=jdbc:mysql://localhost:3306/test
username=root
password=root
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
maxWait=2000

java代码:


public class Demo2Druid {

    public static void main(String[] args) throws Exception {
        //1.从类路径下加载配置文件,获取一个输入流。如果不指定路径,默认是读取同一个包下资源文件
        InputStream inputStream = Demo2Druid.class.getResourceAsStream("/druid.properties");
        //2.使用Properties对象的方法将配置文件中属性加载到Properties对象中
        Properties properties = new Properties();
        //加载了配置文件中所有的属性
        properties.load(inputStream);
        //3.通过druid的工厂类创建连接池
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

        //获取10个连接对象
        for (int i = 1; i <= 11; i++) {
            Connection connection = dataSource.getConnection();
            System.out.println("第" + i + "个连接对象:" + connection);
            //第3个连接关闭
            if (i==3) {
                connection.close();
            }
        }
    }
}

在这里插入图片描述
但是如果超过了数据库最大连接数量:
在这里插入图片描述
但是我们让第三个关闭了连接,相当于还给连接池一个连接对象,所以会打印是以个结果:(有两个地址值是相同的!)
在这里插入图片描述

4 数据工具类再增强

分析

使用Druid连接池来获取连接对象,达到提升访问数据库速度目的

  1. 去掉类中与数据库连接有关的代码
  2. 得到数据库的连接,从连接池中获取
  3. 新加一个方法,获取连接池对象
  4. 在类一开始加载就能够获取连接池(数据源)对象,在静态代码块中创建连接池

代码

package com.aoshen.Test;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class JDBCUtils {
    //声明连接池对象
    private static DataSource dataSource;

    //使用静态,是类加载的时候就创建连接池
    static{
        try {
            //读取配置文件
            InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("druid");
            //获取Properties对象,加载到该对象中
            Properties properties = new Properties();
            //获取配置文件
            properties.load(inputStream);
            //创建druid工厂
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取数据库连接
    public static Connection getConn() throws SQLException {
        return dataSource.getConnection();
    }


    /**
     * 关闭连接
     * 查询调用这个方法
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (statement != null) {
                statement.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭连接
     * 增删改没有结果集
     */
    public static void close(Connection connection, Statement statement) {
        //直接调用上面的方法
        close(connection, statement, null);
    }

    /**
     * 通用的增删改方法
     */
    public static int update(String sql,Object...args){
        Connection conn = null;
        PreparedStatement ps = null;
        //返回影响的行数
        int row = 0;
        try{
            //获取连接
            conn = getConn();
            //获取预编译对象
            ps = conn.prepareStatement(sql);
            //获取元数据,得到有多少占位符
            ParameterMetaData metaData = ps.getParameterMetaData();
            int count = metaData.getParameterCount();
            //循环获取赋值
            for (int i = 0; i < count; i++) {
                ps.setObject(i+1,args[i]);
            }
            //执行SQL语句
            row = ps.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            close(conn,ps);
        }
        return row;
    }

    /**
     * 通用的查询方法
     */
    public static <T> List<T> equery(String sql,Class<T>c,Object...args){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        //创建集合用于接收数据库中查的值
        List<T>list = new ArrayList<>();
        try{
            //获取连接
            conn = getConn();
            //获取预编译对象
            ps = conn.prepareStatement(sql);
            //通过获取元数据给占位符赋值
            ParameterMetaData metaData = ps.getParameterMetaData();
            int count = metaData.getParameterCount();
            for (int i = 0; i < count; i++) {
                ps.setObject(i+1,args[i]);
            }
            //执行sql
            rs = ps.executeQuery();
            //遍历集合,封装到集合中吗,一行数据封装一个对象
            while (rs.next()){
                //每条记录封装成一个对象
                T t = c.newInstance();
                //得到实体类中有哪些列名
                Field[] fields = c.getDeclaredFields();
                //遍历赋值
                for (Field field : fields) {
                    //获取列名
                    String name = field.getName();
                    //获取内容
                    Object value = rs.getObject(name);
                    //因为是私有的,要暴力反射
                    field.setAccessible(true);
                    //把最后得到的值赋值给创建的对象中
                    field.set(t,value);
                }
                //把最后含每一行值的对象添加到集合中
                list.add(t);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            close(conn,ps,rs);
        }
        return list;
    }


}

使用工具类


/**
 * 使用工具类
 */
public class Demo3UseUtils {

    public static void main(String[] args) {
        //使用工具类添加1条记录
        int row = JdbcUtils.update("insert into student values(null,?,?,?)", "嫦娥", 0, "1997-07-07");
        System.out.println("添加了" + row + "条");

        //使用工具类查询所有的数据
        List<Student> students = JdbcUtils.query("select * from student", Student.class);
        //打印
        students.forEach(System.out::println);
    }

}

在这里插入图片描述

小结

修改了连接的获取方式

  1. 在静态代码块中创建连接池对象
  2. 添加了获取数据源的方法
  3. 修改了获取连接的方法,从连接池中获取连接对象
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值