Druid(德鲁伊)数据库连接池

一.数据库连接池的必要性

(一).传统数据库连接模式的的步骤

  1. 在主程序中创建连接
  2. 进行sql操作
  3. 关闭数据库连接

(二).传统数据库连接模式存在的问题

  1. 浪费时间:每次连接时都要验证登录和将connection加载到内存,

  2. 不能大规模的访问数据库:当数据库访问人数过多时,占用大量系统资源,会导致服务器崩溃

  3. 存在内存泄漏问题:每次连接都需要断开连接,如果不断开,程序运行结束,会有创建的连接对象存在内存中一直无法关闭,就会导致java内存泄漏的问题。

内存泄漏:指创建的对象无法被回收

二.数据库连接池技术

(一).数据连接池的思想:

事先在内存中建立一个缓冲池,用来存放一定数量的连接对象,需要时在里面调用,结束时放回缓冲池。

(二).数据库连接池的任务:

管理和释放数据库连接,允许用户使用池内的连接对象,而不需要创建对象。

(三).数据库连接池的规模:

初始化时的数量:由数据库最小连接数来设定;

最大数量:由最大数据库连接数来确定。

当连接数超过了最大连接数,超过的连接就会停止等待连接对象的释放。

(四).工作原理:

在这里插入图片描述

(五).数据库连接池的优点:

  1. 资源重用:
    连接池中的对象需要时取出,不需要被连接池回收

  2. 更快的反应速度:
    事先在池中储备连接对象,初始化已经完成,直接调用。

  3. 数据库共享机制
    多个用户访问同一数据库,通过在应用层的配置,可以避免资源独占。

  4. 避免内存泄漏:
    连接对象统一管理,设置连接对象时间片,超时强制回收。

三.多种开源的数据库连接池

JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource是一个接口,该接口通常由服务器提供。

常见的开源数据库连接池:

DBCP:速度比C3P0快但有bug

c3p0:速度慢,但相对稳定

Proxool:开源连接池,有监控连接池的功能,但稳定性比C3P0差

BoneCP:速度快,开源

Druid:阿里提供的连接池,速度快(不及BoneCP),稳定性好,有监控连接池的功能。

四.学习最主流的数据库连接池Druid

Druid 是阿里提供的数据库连接池,据说是集DBCP 、C3P0 和Proxool 优点于一身的数据库连接池,它是目前国内用到最多的数据库连接池技术。

(一).创建连接(配置文件方式)

  • 依赖
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.31</version>
        </dependency>

        <dependency>
        <!--mysql版本对应-->
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
  • 配置文件
    创建配置文件druid.properties,并输入配置信息
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=12345678
initialSize=10
maxActive=20
  • 详细的配置参数
配置缺省说明
name配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:”DataSource-” + System.identityHashCode(this)
url连接数据库的url,不同数据库不一样。例如:mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username连接数据库的用户名
password连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/使用ConfigFilter
driverClassName根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下)
initialSize0初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
maxActive8最大连接池数量
maxIdle8已经不再使用,配置了也没效果
minIdle最小连接池数量
maxWait获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
poolPreparedStatementsfalse是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
maxOpenPreparedStatements-1要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
validationQuery用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。
testOnBorrowtrue申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
testOnReturnfalse归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testWhileIdlefalse建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
timeBetweenEvictionRunsMillis有两个含义: 1)Destroy线程会检测连接的间隔时间2)testWhileIdle的判断依据,详细看testWhileIdle属性的说明
numTestsPerEvictionRun不再使用,一个DruidDataSource只支持一个EvictionRun
minEvictableIdleTimeMillis
connectionInitSqls物理连接初始化的时候执行的sql
exceptionSorter根据dbType自动识别 当数据库抛出一些不可恢复的异常时,抛弃连接
filters属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
proxyFilters类型是List,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系
  • 封装连接工具类
public class DruidUtils {

    private static DataSource source;

    /**
     * 静态代码块中加载配置文件,随着类的加载而执行
     */
    static {
        try {
            //创建properties对象,用来封装从文件中获取的流数据
            Properties pros = new Properties();
            //采用类加载方式获取文件的内容,并封装成流
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("Druid.properties");
            //将流传入到pros对象中
            pros.load(is);
            //利用工厂类创建数据库连接池
            source = DruidDataSourceFactory.createDataSource(pros);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接  直接使用数据库连接池对象条用getConnection()方法
     * @return
     * @throws Exception
     */
    public static Connection getConnection() throws Exception {
        return source.getConnection();
    }

    /**
     * 关闭连接
     * @param connection
     * @param stm
     * @param rs
     */
    public static void close(Connection connection, Statement stm, ResultSet rs) {
        try {
            if (connection != null) connection.close();
        } catch (Exception throwable) {
            throwable.printStackTrace();
        }
        try {
            if (stm != null) stm.close();
        } catch (Exception throwable) {
            throwable.printStackTrace();
        }
        try {
            if (rs != null) rs.close();
        } catch (Exception throwable) {
            throwable.printStackTrace();
        }
    }

    /**
     * 重载close方法
     */
    public static void close(Connection conn, Statement stm) {
        close(conn, stm, null);
    }

}
  • 测试类
    /**
     * 测试连接是否成功
     * @throws Exception
     */
    @Test
    public void getDruidConnection() throws Exception {
        Connection conn = DruidUtils.getConnection();
        System.out.println(conn);
    }

返回值如下,连接成功
在这里插入图片描述

简易增删改查

  • 实体类
public class ApplicationDO {
    /**
     * 主键ID
     */
    private Long id;

    /**
     * 申请类型 0 未知,1 license,2 soultion,3 both
     */
    private Integer applyType;


    /**
     * teamwork项目名称
     */
    private String teamworkProjectName;

    /**
     * 项目名称
     */
    private String projectName;


    /**
     * 客户名称
     */
    private String customName;


    /**
     * 获取主键ID
     *
     * @return id - 主键ID
     */
    public Long getId() {
        return id;
    }

    /**
     * 设置主键ID
     *
     * @param id 主键ID
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * 获取申请类型 0 未知,1 license,2 soultion,3 both
     *
     * @return apply_type - 申请类型 0 未知,1 license,2 soultion,3 both
     */
    public Integer getApplyType() {
        return applyType;
    }

    /**
     * 设置申请类型 0 未知,1 license,2 soultion,3 both
     *
     * @param applyType 申请类型 0 未知,1 license,2 soultion,3 both
     */
    public void setApplyType(Integer applyType) {
        this.applyType = applyType;
    }


    /**
     * 获取teamwork项目名称
     *
     * @return teamwork_project_name - teamwork项目名称
     */
    public String getTeamworkProjectName() {
        return teamworkProjectName;
    }

    /**
     * 设置teamwork项目名称
     *
     * @param teamworkProjectName teamwork项目名称
     */
    public void setTeamworkProjectName(String teamworkProjectName) {
        this.teamworkProjectName = teamworkProjectName;
    }

    /**
     * 获取项目名称
     *
     * @return project_name - 项目名称
     */
    public String getProjectName() {
        return projectName;
    }

    /**
     * 设置项目名称
     *
     * @param projectName 项目名称
     */
    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }


    /**
     * 获取客户名称
     *
     * @return custom_name - 客户名称
     */
    public String getCustomName() {
        return customName;
    }

    /**
     * 设置客户名称
     *
     * @param customName 客户名称
     */
    public void setCustomName(String customName) {
        this.customName = customName;
    }


    @Override
    public String toString() {
        return "ApplicationDO{" +
                "id=" + id +
                ", applyType=" + applyType +
                ", teamworkProjectName='" + teamworkProjectName + '\'' +
                ", projectName='" + projectName + '\'' +
                ", customName='" + customName + '\'' +
                '}';
    }
}
  • 增删改查
/**
     * 查询
     * @throws Exception
     */
    @Test
    public void Select() throws Exception {
        //因为获取连接创建的是静态方法  直接使用类名.方法名调取  获得连接即可
        Connection conn= DruidUtils.getConnection();
        String sql="SELECT * FROM licenx_application";
        //获取执行者对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
        ResultSet rs = pstmt.executeQuery();
        ApplicationDO applicationDO;
        List<ApplicationDO> applicationDOs=new ArrayList<>();
        //遍历ResultSet结果集  存入List
        while (rs.next()){
            applicationDO=new ApplicationDO();
            applicationDO.setId(rs.getLong("id"));
            applicationDO.setCustomName(rs.getString("custom_name"));
            applicationDO.setApplyType(rs.getInt("apply_type"));
            applicationDO.setTeamworkProjectName(rs.getString("teamwork_project_name"));
            applicationDO.setProjectName(rs.getString("project_name"));
            applicationDOs.add(applicationDO);

        }
        //输出list查看
        for (ApplicationDO applicationDO1 : applicationDOs) {
            System.out.println(applicationDO1);
        }

        DruidUtils.close(conn,pstmt,rs);
    }


    /**
     * 插入
     * @throws Exception
     */
    @Test
    public void insert() throws Exception {
        //获取数据库连接
        Connection conn=DruidUtils.getConnection();
        String sql="insert into licenx_application (custom_name, apply_type, teamwork_project_name, project_name) values (?, ?, ?, ?)";
        //获取执行者对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
        //设置sql语句中的?值
        pstmt.setObject(1,"测试");
        pstmt.setObject(2,1);
        pstmt.setObject(3,"测试");
        pstmt.setObject(4,"测试");
        int i = pstmt.executeUpdate();
        if (i>0){
            System.out.println("添加成功");
        }
        //释放资源
        DruidUtils.close(conn,pstmt);
    }


    /**
     * 删除
     * @throws Exception
     */
    @Test
    public void delete() throws Exception {
        //获取连接
        Connection conn=DruidUtils.getConnection();
        String sql="DELETE from licenx_application where id=?";
        //获取执行者对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
        //设置sql中的?值
        pstmt.setObject(1,251757598242504708l);
        int i = pstmt.executeUpdate();
        if (i>0) System.out.println("删除成功");
        //关闭资源
        DruidUtils.close(conn,pstmt);

    }


    /**
     * 更新
     * @throws Exception
     */
    @Test
    public void update() throws Exception {
        //获取连接
        Connection conn=DruidUtils.getConnection();
        String sql="UPDATE licenx_application SET teamwork_project_name=? WHERE id=?";
        //获取执行者对象
        PreparedStatement pstmt = conn.prepareStatement(sql);
        //设置sql中?的值
        pstmt.setObject(1,"99999");
        pstmt.setObject(2,251757598242504706l);
        int i = pstmt.executeUpdate();
        if (i>0) System.out.println("修改成功");
        //释放资源
        DruidUtils.close(conn,pstmt);

    }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值