• Python工程师Java之路(w)数据库连接池Druid


    概述

    • 初阶数据库访问的步骤是【创建连接=>执行SQL=>关闭连接】,有如下不足:
      1、创建数据库连接会浪费时间
      2、大量访问时,频繁 GC 会导致CPU负载过高
      3、如果改为不关闭连接,则会长期占用内存
    • 对此,引入“缓冲池”思想:
      在“缓冲池”中预备一定数量的数据库连接
      当需要访问数据库时,就从“缓冲池”中取出一个,用完后放回
      当大量访问时,“缓冲池”中的数据库连接不够,就新建数据库连接
      当访问量变少,就关闭部分数据库连接,减少到初始(下限)数量
    • 数据库连接池(connection pool)
      负责分配、管理和释放数据库连接
      允许应用程序重复使用一个现有的数据库连接,而不是新建一个
    • 数据库连接的数量下限:
      连接池将保证一定数量的连接,即使它们没被使用
    • 数据库连接的数量上限:
      请 求 数 > 最 大 连 接 数 请求数>最大连接数 > 时,后面请求将被加入 等待队列
    • 数据库连接池优点:
      1、提高反应速度
      2、充分而均衡地利用CPU和内存,降低 CPU高负载 或 内存泄漏 的风险

    数据库连接池

    获取空闲的数据库连接

    DRUID

    DRUID是阿里巴巴开源平台上一个数据库连接池实现,代码如下

    pom.xml

    
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>8.0.31version>
    dependency>
    
    <dependency>
        <groupId>com.alibabagroupId>
        <artifactId>druidartifactId>
        <version>1.2.15version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    入门代码

    import com.alibaba.druid.pool.DruidDataSource;
    import com.alibaba.druid.pool.DruidPooledConnection;
    
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class Hello {
        public static void main(String[] args) throws SQLException {
            //TODO 1 创建数据库连接池
            DruidDataSource d = new DruidDataSource();
    
            //TODO 2 设置MySQL基本连接参数
            d.setDriverClassName("com.mysql.cj.jdbc.Driver"); //驱动全类名
            d.setUrl("jdbc:mysql://localhost:3306"); //JDBC的URL
            d.setUsername("root"); //数据库用户名
            d.setPassword("123456"); //数据库密码
    
            //TODO 3 设置缓冲池参数
            d.setInitialSize(1); //初始化时的连接数
            d.setMaxActive(2); //同时活跃的最大连接数
            d.setMinIdle(1); //空闲时的最小连接数
            d.setMaxWait(3000L); //用户等待最大毫秒数
    
            //TODO 4 访问数据库
            DruidPooledConnection c = d.getConnection();
            //用于执行静态SQL并返回结果的对象
            Statement s = c.createStatement();
            //执行SQL(默认情况下,每个Statement对象只能同时打开一个ResultSet对象)
            ResultSet r = s.executeQuery("SELECT 8 AS a,'x' AS b UNION ALL SELECT 9 AS a,'y' AS b");
            //获取元数据
            ResultSetMetaData m = r.getMetaData();
            System.out.println(m.getColumnName(1) + "\t" + m.getColumnName(2));
            //获取数据
            while (r.next()) {
                System.out.println(r.getInt(1) + "\t" + r.getString(2));
            }
            //释放ResultSet,释放Statement,归还数据库连接
            r.close();
            s.close();
            c.close();
    
            //TODO 5 连接数测试
            (new MyThread()).start();
            for (int i = 0; i < 3; i++) {
                d.getConnection();
            } //上面设置了最大连接数2,第3个连接超时3秒后报错
        }
    
        static class MyThread extends Thread {
            @Override
            public void run() {
                for (int i = 1; i < 5; i++) {
                    try {
                        Thread.sleep(999L);
                        System.out.println("过了" + i + "秒");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    代码运行结果打印

    封装数据库连接池工具类

    import com.alibaba.druid.pool.DruidDataSource;
    import com.alibaba.druid.pool.DruidPooledConnection;
    
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class DatabaseConnectionPool {
        private final DruidDataSource druidDataSource;
    
        public DatabaseConnectionPool() {
            druidDataSource = new DruidDataSource();
            //始化时的连接数量
            druidDataSource.setInitialSize(5);
            //同时活跃的最大连接数
            druidDataSource.setMaxActive(20);
            //空闲时的最小连接数
            druidDataSource.setMinIdle(1);
            //获取连接等待的最大毫秒数,超时抛出异常,设-1表示一直等待
            druidDataSource.setMaxWait(-1L);
            //借出连接时 是否测试,false不测试 提升性能
            druidDataSource.setTestOnBorrow(false);
            //归还连接时 是否测试
            druidDataSource.setTestOnReturn(false);
            //每隔30秒运行一次 空闲连接回收器
            druidDataSource.setTimeBetweenEvictionRunsMillis(30 * 1000L);
            //池中 空闲30分钟的连接将被回收
            druidDataSource.setMinEvictableIdleTimeMillis(30 * 60 * 1000L);
        }
    
        public void setDBCP(String driverClass, String jdbcUrl) {
            druidDataSource.setDriverClassName(driverClass);
            druidDataSource.setUrl(jdbcUrl);
        }
    
        public void setDBCP(String driverClass, String jdbcUrl, String user, String pwd) {
            setDBCP(driverClass, jdbcUrl);
            druidDataSource.setUsername(user);
            druidDataSource.setPassword(pwd);
        }
    
        public void selectPrint(String sql) throws SQLException {
            DruidPooledConnection c = druidDataSource.getConnection();
            //获取 用于执行静态SQL并返回结果的对象
            Statement s = c.createStatement();
            //执行SQL(默认情况下,每个Statement对象只能同时打开一个ResultSet对象)
            ResultSet r = s.executeQuery(sql);
            //获取元数据
            ResultSetMetaData m = r.getMetaData();
            //获取列数
            int columnCount = m.getColumnCount();
            //打印列名
            System.out.print("行号");
            for (int i = 1; i <= columnCount; i++) {
                System.out.print("\t|\t" + m.getColumnName(i));
            }
            System.out.println();
            //打印数据
            while (r.next()) {
                System.out.print(r.getRow());
                for (int i = 1; i <= columnCount; i++) {
                    System.out.print("\t|\t" + r.getObject(i));
                }
                System.out.println();
            }
            //释放ResultSet,释放Statement,归还数据库连接
            r.close();
            s.close();
            c.close();
        }
    
        public static void main(String[] args) throws SQLException {
            //测试
            DatabaseConnectionPool d = new DatabaseConnectionPool();
            d.setDBCP("com.mysql.cj.jdbc.Driver", "jdbc:mysql://localhost:3306", "root", "123456");
            d.selectPrint("SELECT 8 AS a,'x' AS b UNION ALL SELECT 9 AS a,'y' AS b");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
  • 相关阅读:
    分布式监控系统——Zabbix(2)部署
    33.【C/C++ char 类型与Ascii大整合,少一个没考虑你打我】
    基于Java的国内外重大新闻展示平台的设计与实现
    java计算机毕业设计springboot+vue青少年编程在线考试系统
    TIDB 性能测试(TIUP-TPCC)
    Python二维码生成工具
    214页(10万字)以数据驱动为核心的区域医疗数据中台
    使用 vve-i18n-cli 来一键式自动化实现国际化
    leetcode 刷题 log day 42
    带你玩转Redis 的String 数据类型
  • 原文地址:https://blog.csdn.net/Yellow_python/article/details/128194869