• 实现一个简易的数据库连接池


    数据库连接池的作用:

    1. 资源重用

    当多个用户频繁的去对数据库进行读写操作时,会不间断的创建Connection,在数据库开始读写数据之前,把资源过多的分配给创建连接释放连接上,这笔开销得不偿失.数据库连接池的对连接Connection的资源回收机制对此做出了优化

    2. 更快的系统响应速度

    数据库连接池一旦初始化,用户获取的Connection不再创建新的,而是从现有的容器里面取,使得直接利用成为可能,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间

    3. 新的资源分配手段

    对于多应用共享同一数据库的系统而言 ,某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源

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

    数据库连接池提供连接超时设定,超时后会重试,针对用户获取到的不健康的Connection,同样会重新分配新的连接,从而避免了常规数据库连接操作中可能出现的资源泄漏

    实现一个简单的数据库连接池

    目标:

    • 要实现的数据库连接池,统一注册驱动(替换每一次连接数据库都要注册驱动的时代)
    • 用户想对数据库进行进一步的操作,需要在数据库连接池中获取连接Connection
    • 用户对队数据库读写完毕之后, 连接池回收当前的Connection

    两个容器

    数据库连接池 = 空闲连接池 + 工作连接池

    三个重要的参数

    • 最大连接数
      • 最大连接数是对Connection总数的限制 一般是((核心数 * 2) + 有效磁盘数)
    • 空闲连接数
      • 空闲连接数 表示当前的空闲连接池中的Connection的数量,我们给他规定最大值和最小值
      • 当前值 < 最大连接数 表示用户有机会获取连接
        • 如果 空闲连接池的size>0 直接获取连接
        • 否则 创建一个新的Connection给用户
      • 当前值 >= 最大连接数 Connection的创建达到了上限,用户只能等待重试
    • 工作连接数
      • 工作连接数 表示 当前工作连接池中的Connection的数量

    获取连接经历什么?

    1. 空闲连接池中的弹出一个Connection
    2. 把当前的Connection加入到工作连接池

    连接是如何被回收的?

    1. 如果空闲连接池未满.直接添加进去
    2. 把工作连接池中相应的连接移除
    3. 如果空闲连接池满了.直接close()掉
    4. 把工作连接池中相应的连接移除

    配置文件读取工具类

    public class propertiesUtil {
    
        private static Properties configObj = new Properties();
    
        static{
            // 使用类加载器读取放在src下的pool.properties文件
     InputStream connectionPool = Thread.currentThread().getContextClassLoader().getResourceAsStream("pool.properties"); InputStreamReader inputStreamReader = new InputStreamReader(connectionPool); try { configObj.load(inputStreamReader); } catch (IOException e) { e.printStackTrace(); } } public static String getValue(String key){ return configObj.getProperty(key); } }

    定义接口,规范我们的连接池的方法

    public interface myConnectionPool  {
        /**
         * 获取连接
         * @return
         */
        public Connection getConnection();
    
        /**
         * 释放连接
         * @param connection
         */
        public void releaseConnection(Connection connection);
    }

    具体的实现类实现myConnectionPool接口

    public class ConnectionPool implements myConnectionPool
    {
        // 线程安全的两个容器,分别存放空闲线程数和活动的线程数
        private List<Connection> freeConnection = new CopyOnWriteArrayList<>();
        private List<Connection> activeConnection = new CopyOnWriteArrayList<>();
        // 原子类 标记的是 空闲池的存放的连接数
        private AtomicInteger atomicInteger;
    
        public ConnectionPool() {
          
            this.atomicInteger = new AtomicInteger(0);
            // 初始化空闲连接池
            init();
        }
    
        // 初始空闲连接池
        public void init() {
            // 获取连接数,给freeConnection 池添加指定数量的连接数
            for (int i = 0; i < Integer.valueOf(propertiesUtil.getValue("initConnections")); i++) {
                // 创建连接
                Connection connection = newConnection();
                if (null != connection) {
                    // 添加到容器
                    freeConnection.add(connection);
                }
            }
        }
    
        // 获取连接
        @Override
        public synchronized Connection getConnection() {
            Connection connection=null;
            // 判断是否达到了最大连接数--> 决定给用户连接还是让他等待
            if (atomicInteger.get()<Integer.valueOf(propertiesUtil.getValue("maxActiveConnetions"))){
                // 当前小于最大的连接数,直接给当前的用户连接
                if (freeConnection.size()>0){ // 空闲线程里面有直接从空闲线程里面取
                    connection  = freeConnection.remove(0);
                }else{  // 空闲线程里面没有,直接创建一个新的连接
                    connection = newConnection();
                }
                // 判断连接是否可用
                 if(isAvailable(connection)){
                     // 添加到一个活动线程里面
                     activeConnection.add(connection);
                 }else{ // 如果连接不可用,递归
                     //  如果连接不可用的话,说明有一次newConnection()失败了,我们得 atomicInteger.decrementAndGet(); 把newConnection()里面的原子增加去掉
                     atomicInteger.decrementAndGet();
                     connection = getConnection();
                 }
            }else{
                // 等待
                try {
                    wait(Integer.valueOf(propertiesUtil.getValue("connTimeOut")));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return connection;
        }
    
        // 释放本次连接  ; 把本次连接从活动池 转移到 空闲池
        @Override
        public synchronized void releaseConnection(Connection connection) {
            // 判断连接是否可用
            if(isAvailable(connection)){ // 可用
                // 回收
                // 判断空闲池是否满了
                if(freeConnection.size()<Integer.valueOf(propertiesUtil.getValue("maxConnections"))){
                    // 未满
                    freeConnection.add(connection);
                }else{
                    // 满了
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                // 移除出去当前的这个连接
                activeConnection.remove(connection);
                atomicInteger.decrementAndGet();
                // 现在可能有连接正在等待,既然这里释放了,那么就唤醒全部等待的线程
                notifyAll();
            }else{ // 不可用
                throw new RuntimeException("连接回收异常");
            }
        }
    
    
        // 创建新的连接
        public Connection newConnection() {
            try {
                // 注册驱动
                Class.forName(propertiesUtil.getValue("driverName"));
                // 获取连接
                Connection connection = DriverManager.getConnection(
                        propertiesUtil.getValue("url"),
                        propertiesUtil.getValue("userName"),
                        propertiesUtil.getValue("password"));
                // 原子增加
                atomicInteger.addAndGet(1);
                return connection;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        // 判断连接是否可用
        public boolean isAvailable(Connection connection){
            try {
                if (null==connection||connection.isClosed()){
                    return false;
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return true;
        }
    }

    配置文件

    # 数据库相关
    driverName=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/text
    userName=root
    password=root
    
    # 空闲池的 最小数
    minConnections=1
    # 空闲池的 最大数
    maxConnections=10
    # 初始化的连接数
    initConnections=5
    
    # 本次连接超时时间(重试时间)
    connTimeOut=1000
    # 最大的连接数
    maxActiveConnetions=10

    此文来源于:https://www.cnblogs.com/ZhuChangwu/p/11150572.html

  • 相关阅读:
    Python 中的map函数,filter函数,reduce函数
    编程中,static的用法详解
    C++ list容器系列功能函数详解
    python中的configparser类
    310实验室OTL问题----将写好的C++文件转换成Python文件,并将数据可视化
    310实验室OTL问题
    常量指针、指针常量、指向常量的指针常量
    Iterator迭代器的相关问题
    struts2中action中的通配符
    struts2访问servlet API
  • 原文地址:https://www.cnblogs.com/JonaLin/p/11307579.html
Copyright © 2020-2023  润新知