首页 > 数据库 >Database Connection Pool 数据库连接池-01-概览及简单手写实现

Database Connection Pool 数据库连接池-01-概览及简单手写实现

时间:2024-03-14 10:56:13浏览次数:27  
标签:01 String Database 数据库 private Connection static 连接 连接池

拓展阅读

第一节 从零开始手写 mybatis(一)MVP 版本

第二节 从零开始手写 mybatis(二)mybatis interceptor 插件机制详解

第三节 从零开始手写 mybatis(三)jdbc pool 从零实现数据库连接池

第四节 从零开始手写 mybatis(四)- mybatis 事务管理机制详解

连接池的作用

资源重用

由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,
另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。

更快的系统响应速度

数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。
对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。

新的资源分配手段

对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,使用数据库连接池技术。
设置某一应用最大可用数据库连接数,避免某一应用独占所有数据库资源。

统一的连接管理,避免数据库连接泄漏

在较为完备的数据库连接池实现中,可根据预先设定的连接占用超时时间,强制收回被超时占用的连接。
从而避免了常规数据库连接操作中可能出现的资源泄漏(当程序存在缺陷时,申请的连接忘记关闭,这时候,就存在连接泄漏了)。

中间件

常见实现对比

参考网上资料Druid > TomcatJDBC > DBCP > C3P0,BoneCP 的性能方面没有深入比较,应该和 Tomcat Jdbc 差不多。

对于小型的系统,并发压力不大时,选择哪一种数据库连接池差别不会很大,主要考虑的应该是连接池的稳定性。

当并发量较高时,一般不会选择使用 DBCP 和C3P0,选 Druid 是较好的。

手动实现

自己实现一个简化版,便于理解原理。

  • 连接池接口
public interface IPool {
    /**
     * 获取新的数据库链接
     * @return 数据库链接
     */
    PoolConnection getPoolConnection();
}

其中 PoolConnection 如下:

public class PoolConnection {
    /**
     * 是否繁忙
     */
    private volatile boolean isBusy;

    /**
     * 数据库链接信息
     */
    private Connection connection;
}
  • 核心实现
public class PoolImpl implements IPool {

    /**
     * 数据库驱动
     */
    private final String jdbcDriver;

    /**
     * 数据库连接
     */
    private final String jdbcUrl;

    /**
     * 数据库用户名
     */
    private final String username;

    /**
     * 数据库密码
     */
    private final String passowrd;

    /**
     * 连接池大小
     */
    private final int size;

    /**
     * 数据库连接池列表
     */
    private List<PoolConnection> poolConnections = new ArrayList<>();

    public PoolImpl(String jdbcDriver, String jdbcUrl, String username, String passowrd, int size) {
        this.jdbcDriver = jdbcDriver;
        this.jdbcUrl = jdbcUrl;
        this.username = username;
        this.passowrd = passowrd;
        this.size = size;

        init();
    }

    private void init() {
        try {
            //1. 注册数据库连接信息
            Driver sqlDriver = (Driver) Class.forName(jdbcDriver).newInstance();
            DriverManager.registerDriver(sqlDriver);

            //2. 初始化连接池
            initConnectionPool();
        } catch (InstantiationException | IllegalAccessException | SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化链接
     * @throws SQLException sql 异常
     */
    private void initConnectionPool() throws SQLException {
        for(int i = 0; i < size; i++) {
            Connection connection = DriverManager.getConnection(jdbcUrl, username, passowrd);
            PoolConnection poolConnection = new PoolConnection(false, connection);
            poolConnections.add(poolConnection);
        }
    }

    @Override
    public PoolConnection getPoolConnection() {
        if(poolConnections.size() <= 0) {
            return null;
        }

        PoolConnection poolConnection = getRealConnection();
        while (poolConnection == null) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            poolConnection = getRealConnection();
        }

        return poolConnection;
    }

    /**
     * 获取数据库链接对象
     * @return 数据库链接对象
     */
    private synchronized PoolConnection getRealConnection() {
        for(PoolConnection poolConnection : poolConnections) {
            // 寻找不处于繁忙状态的连接
            if(!poolConnection.isBusy()) {
                Connection connection = poolConnection.getConnection();

                // 测试当前连接是否有效
                try {
                    if(!connection.isValid(5000)) {
                        Connection validConnection = DriverManager.getConnection(jdbcUrl, username, passowrd);
                        poolConnection.setConnection(validConnection);
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }

                // 设置为繁忙
                poolConnection.setBusy(true);
                return poolConnection;
            }
        }

        return null;
    }
}
  • 线程池管理类

使用单例

public class PoolManager {

    /**
     * 连接池持有类
     */
    private static class PoolHolder {
        private static String url = "";
        private static String driver = "";
        private static String username = "";
        private static String password = "";
        private static int size = 10;

        private static IPool poolImpl = new PoolImpl(driver, url, username, password, size);
    }

    /**
     * 内部类单利模式产生使用对象
     * @return 单例
     */
    public static IPool getInstance() {
        return PoolHolder.poolImpl;
    }
}

标签:01,String,Database,数据库,private,Connection,static,连接,连接池
From: https://www.cnblogs.com/houbbBlogs/p/18072357

相关文章

  • L2-001 紧急救援
    这道题就是在dijkstra的基础上增加了一些东西。代码有参考别人,最后一步的处理很好。#include<bits/stdc++.h>usingnamespacestd;constintmaxv=0x7fffffff;intedges[510][510];//从i到j的长度intdist[510];//最短路径boolcheck[510];//是否在集合之中intnum[510......
  • P5304 [GXOI/GZOI2019] 旅行者
    Mikuuu准备投身于ACM的潮流中,失踪人口回归啦!这个题目的思路还是非常有趣的,因为我们可以注意到,两个可能成为答案兴趣点之间的最短路不应该经过了第三个点,如果经过了,显然和第三个点之间的最短路会更小,则原来的两个点之间不应该成为答案。考虑到这一点,我们可以想到建枚举每一条边,......
  • Linux内核编译(版本6.0以及版本v0.01)并用qemu驱动
    系统环境:ubuntu-22.04.1-desktop-amd64目标平台:x86i386内核版本:linux-6.0.1linux-0.0.1环境配置修改root密码sudopasswd修改软件源(非必要)vmtools安装(实现win-linux软件互传)安装一些必须的软件:sudoaptinstallbuild-essentialopenssh-servervimnet-toolsgc......
  • 【NOIP2013模拟联考8】匹配(match) 题解
    B组都说看不懂……我也解释不清啊……只能写这么详细了ac自动机ac自动机上dp怎么才能判定一个母串是否包含几个模式串?我们可以想到ac自动机,考虑对模式串建ac自动机,如果我们跑到了一个标记为tail的节点,说明我们的母串包含了这一个模式串。所以我们设\(f[i][s][......
  • 【Java面试题-基础知识01】Java数据类型四连问?
    一、Java中的基础数据类型有哪些?Java中的基本数据类型包括:1.byte:8位有符号整数,范围为-128到127。2.short:16位有符号整数,范围为-32768到32767。3.int:32位有符号整数,范围为-2147483648到2147483647。4.long:64位有符号整数,范围为-9223372036854775808到9223372036854775807。5.......
  • 2019蓝桥杯省赛B组
    2019蓝桥杯省赛B组A.组队方法一:人脑计算(每次选最大,但是一个人不能当两个位)最大值:98+99+98+97+98法二:枚举#include<iostream>using namespace std;//每个位置各编号的评分情况int one[20] = {97, 92, 0, 0, 89, 82, 0, 0, 0, 95, 0, 0, 94, 0, 0, 0......
  • [蓝桥杯 2019 省 A] 填空问题 E
    一、题目描述[蓝桥杯2019省A]填空问题ERSA解密二、问题简析本问题可以分成三部分求解:1、求\(p\)和\(q\):利用唯一分解定理,参考P1075[NOIP2012普及组]质因数分解2、求\(e\):利用拓展欧几里得定理,参考P1082[NOIP2012提高组]同余方程和拓展欧几里得算法3、......
  • 洛谷P6866 [COCI2019-2020#5] Emacs
    题目描述给定一个n×m 的只含有 . 和 * 的矩阵。矩阵中 * 形成一些不重叠的长方形。它们不在边缘或顶点接触。求长方形有多少个?输入格式第一行:两个正整数 n 和 m。以下 n 行:表示题目描述中的矩阵。矩阵只含有 . 和 *。输出格式一行一个非负整数,你的答......
  • C++:[NWRRC2015] Concatenation(洛谷)P7050
    题目描述FamousprogrammerGennadylikestocreatenewwords.Onewaytodoitistoconcatenateexistingwords.Thatmeanswritingonewordafteranother.Forexample,ifhehaswords cat and dog,hewouldgetaword catdog,thatcouldmeansomething......
  • L1-011 A-B(C和C++)
    题目:本题要求你计算A−B。不过麻烦的是,A和B都是字符串——即从字符串A中把字符串B所包含的字符全删掉,剩下的字符组成的就是字符串A−B。输入格式:输入在2行中先后给出字符串A和B。两字符串的长度都不超过104,并且保证每个字符串都是由可见的ASCII码和空白字符组成,最后以换行......