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

概述

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

数据库连接池

获取空闲的数据库连接

DRUID

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

pom.xml

<!-- MySQL的JDBC -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.31</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.15</version>
</dependency>

入门代码

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();
                }
            }
        }
    }
}

代码运行结果打印

封装数据库连接池工具类

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");
    }
}

猜你喜欢

转载自blog.csdn.net/Yellow_python/article/details/128194869
今日推荐