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

news2024/12/25 13:31:07

文章目录

  • 一.数据库连接池的必要性
    • (一).传统数据库连接模式的的步骤
    • (二).传统数据库连接模式存在的问题
  • 二.数据库连接池技术
    • (一).数据连接池的思想:
    • (二).数据库连接池的任务:
    • (三).数据库连接池的规模:
    • (四).工作原理:
    • (五).数据库连接池的优点:
  • 三.多种开源的数据库连接池
  • 四.学习最主流的数据库连接池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);

    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/192977.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5 -【Faster R-CNN】之 AnchorGenerator 代码精读

【Faster R-CNN】之 AnchorGenerator 代码精读1、anchor 的 size 和 aspect_ratios2、计算以中心坐标为 (0, 0) 的 anchor3、将 anchor 映射到原图上4、代码汇总anchor 的作用&#xff1a;anchor 是用来做辅助计算的&#xff0c;用于和 &#xff08;上节课说的&#xff0c;由RP…

共享模型之内存(一)

1.Java内存模型 1>.JMM即Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等; 2>.JMM体现在以下几个方面: ①.原子性 - 保证指令不会受到线程上下文切换的影响; ②.可见性 - 保证指令不会受cpu缓存的影响; ③.有序…

大型会场活动线上保障方案

背景 为保证活动上线后的质量&#xff0c;大型会场活动上线前通常会预设一些线上可能出现的问题&#xff0c;提前制定保障方案。 这些与活动保障相关的问题可能与App端上的容器环境有关&#xff0c;也可能与大盘用户设备特征有关&#xff0c;问题的处理方案会影响活动的线上效…

《啊哈算法图的遍历》(14张图解)

目录 前言 一&#xff0c;dfs和bfs是什么 二&#xff0c;城市地图--图的深度优先遍历 三&#xff0c;最少转机--图的广度优先遍历 前言 &#x1f33c;说爱你&#xff08;超甜女声版&#xff09; - 逗仔 - 单曲 - 网易云音乐 1月22日一个女孩加了我&#xff0c;她和我聊音…

adb常用指令合集

adb文件管理指令 1.复制设备里的文件到电脑 adb pull <设备里的文件路径> [电脑上的目录] 电脑上的目录 参数可以省略&#xff0c;默认复制到当前目录 例&#xff1a;adb pull /data/tsplogtool /home/jxq/文档/场景魔方 2.复制电脑里的文件到设备 adb push <电脑上的…

浅谈未来10年IT行业的变局与抉择,一文带你认识元宇宙

一. 困局据国家就业部门最新统计数据报告&#xff0c;2022年应届毕业生的数量首次突破1000万大关。其中研究生达到130万&#xff0c;985、211等名校毕业生75万&#xff0c;普通本科毕业生470万&#xff0c;专科生460万&#xff0c;另外还有几十万的归国留学生&#xff01;但这还…

《从0开始学大数据》之Spark性能优化案例

基于软件性能优化原则和 Spark 的特点&#xff0c;Spark 性能优化可以分解为下面几步。 性能测试&#xff0c;观察 Spark 性能特性和资源&#xff08;CPU、Memory、Disk、Net&#xff09;利用情况。分析、寻找资源瓶颈。分析系统架构、代码&#xff0c;发现资源利用关键所在&a…

【前端】Vue项目:旅游App-(17)home:页面滚动显示搜索栏、节流、时间同步

文章目录目标过程与代码页面滚动到目标位置显示搜索框优化&#xff1a;节流搜索栏显示时间同步效果总代码修改或添加的文件search-bar.vueuseScroll.jsstore的main.jsformatDate.jshome.vue参考本项目博客总结&#xff1a;【前端】Vue项目&#xff1a;旅游App-博客总结 目标 …

HDFS文件浏览器功能OOM排查

现象描述 涉及HDFS文件浏览器的某个功能运行一段时间后会出现OOM的情况 错误日志如下&#xff1a; service.log.2023-02-01-0.log:java.lang.OutOfMemoryError: Java heap space排查过程 需要查看dump文件排查一下造成OOM的原因 查看jvm参数如下&#xff1a; java -Duser.t…

一文讲明Docker的基本使用,常见Docker命令使用 、Docker的安装使用等【详细说明+图解+概念+实践】

一个混迹于Github、Stack Overflow、开源中国、CSDN、博客园、稀土掘金、51CTO等 的野生程序员。 目标&#xff1a;分享更多的知识&#xff0c;充实自己&#xff0c;帮助他人 GitHub公共仓库&#xff1a;https://github.com/zhengyuzh 以github为主&#xff1a; 1、分享前端后端…

【Python合集系列】2023兔年吉祥,新的一年希望放烟花的人跟看烟花的人都能平平安安哦~(附多种源码)

前言 希望放烟花的人跟看烟花的人都能平平安安。 &#x1f440; NICE TO MEET YOU :)&#x1f319; 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝白嫖源码福利&#xff0c;请移步至CSDN社区或文末公众hao即可免费。 ​哈喽&#xff01;我是木子&#xff0c;新…

设计模式之适配器模式,以C++为例。

今天来盘一盘适配器模式。适配器&#xff1a;顾名思义&#xff0c;就是让原本不合适的变为合适的&#xff0c;好似一对男女&#xff0c;没有中间的媒婆是不会互相了解的&#xff0c;好像不太恰当&#xff0c;就这么解释吧&#xff0c;只有有了这个中间人他们才会产生联系&#…

智能驾驶开启高精定位新赛道,这家供应商正加码布局海外市场

高工智能汽车研究院监测数据显示&#xff0c;2022年1-11月中国市场乘用车前装标配搭载NOA交付达到18.38万辆&#xff0c;同比增长91.86%&#xff1b;同时&#xff0c;NOA搭载的车型配置价格还在不断下滑&#xff0c;正在把NOA的配置拉至15万元价格区间。 而作为高精定位&#x…

面向对象——static(静态)Math类自定义工具类代码块

目录 static&#xff08;静态&#xff09;关键字 static的注意事项 static的优点和缺点 应用场景 自定义工具类 代码块 static&#xff08;静态&#xff09;关键字 static是一个修饰符&#xff0c;用于修饰成员&#xff08;成员变量 、成员方法&#xff09;static的特点…

Redis处理client连接数过多,大量空闲链接无法释放问题

打开redis命令终端&#xff0c;输入&#xff1a; client list 查看连接数&#xff0c;用于返回所有连接到服务器的客户端信息和统计数据 参数解析&#xff1a; id: 唯一的64位的客户端ID(Redis 2.8.12加入)。 addr: 客户端的地址和端口 fd: 套接字所使用的文件描述符 age…

python真的很骚可惜你不会

python基本语法 &#x1f4d2;博客主页&#xff1a; 微笑的段嘉许博客主页 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐留言&#x1f4dd; &#x1f4cc;本文由微笑的段嘉许原创&#xff01; &#x1f4c6;51CTO首发时间&#xff1a;&#x1f334;2023年1月日3…

redis分布式缓存

文章目录一、redis持久化1.1.RDB持久化1.1.1.执行时机1.1.2.RDB原理1.1.3.小结1.2.AOF持久化1.2.1.AOF原理1.2.2.AOF配置1.2.3.AOF文件重写1.2.4.小结1.3.RDB与AOF对比二、Redis主从集群2.1.集群结构2.2.准备实例和配置2.3.启动2.4.开启主从关系2.5.测试2.6.主从数据同步原理2.…

Codeforces Round #848 (Div. 2) A-E 赛时思路+正解

青大蒟蒻第一次在正式的div2div2div2中AcAcAc了五道题&#xff0c;也是小蒟蒻有史以来发挥最好的一场&#xff0c;这场过后我的cf也许可能也要变成黄了。 A. Flip Flop Sum 题意&#xff1a;给定一个a——ia——ia——i数组&#xff0c;权值仅为1或-1&#xff0c;我们选择相邻…

《死亡空间》重制回归!无法启动怎么办?

作为科幻生存恐怖系列的经典之作&#xff0c;《死亡空间》在推出15年后再次回归&#xff0c;果然引发热潮。精美震撼的科幻场景&#xff0c;强烈的视觉画面&#xff0c;加上阴森的3D 音效&#xff0c;重制版提升了身临其境之感&#xff0c;完全是沉浸式恐怖体验&#xff0c;只能…

红外遥控数码管显示

红外遥控器实物图红外遥控器接口电路数码管接口电路红外遥控数码管显示程序源代码/**************************红外遥控数码管显示************************** * 单片机&#xff1a;51单片机* 开发环境&#xff1a;keil * 名称:红外遥控数码管显示 * 功能&#xff1a;遥控器红外…