使用工厂模式+单例模式实现[连接池]应用


前言

本章介绍使用工厂模式+单例模式实现数据库连接池,基于池思想的各种实现我们接触的很多,如数据库连接池,redis连接池,线程池等等,在第三方框架下我们只需要书写好一下配置即可完成对池的使用。 而我们抽象出来的池一般都是为了解决频繁创建某资源而造成的服务器压力,我们将创建某资源的步骤交给池管理,我们只需要调用即可。 今天我们说的便是数据库连接池,数据库连接池中存放的都是Connection对象,所以说池对象中必然是要有一个容器来存放这些对象的,而这个容器是无界的吗?我们一般都会设置一个最大的数量,并且基于我们的服务器性能,连接池在各个服务器上的性能是不均衡的,所以我们应该有一个最大连接数并应该是手动控制,容器在池对象初始化中也是要有一个默认容量大小的。当我们的连接池运行起来之后,我们也需要设置一些连接的过期时间,当前的连接数,空闲连接数等等。 今天我们完成的数据库连接池只是一个Mini版,并没有太过复杂的属性和功能,我们就借助一下连接池基本的属性来介绍如何自己去实现一个数据库连接池。 上代码!

Pool抽象父类

package com.xzq.Cases.factory;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 自定义连接池 getInstance(),返回Pool的唯一实例,第一次调用时将执行构造函数
 * 构造函数Pool调用驱动装载loadDrivers()函数,createPool()函数创建连接池,loadDriver()装载驱动
 * getConnection()返回一个连接实例,getConnection(long time)添加时间限制
 * freeConnection(Connection con)将con连接实例返回连接池,getnum()返回空闲连接数
 * getnumActive()返回当前使用的连接数
 */
public abstract class Pool {
    public String propertiesName = "connection-INF.properties";

    private   static Pool instance = null;  //定义唯一实例
    protected int maxConnect = 100;         //最大连接数
    protected int normalConnect = 10;       //保持连接数
    protected String driverName = null;     //驱动字符串
    protected Driver driver = null;         //驱动变量

    protected Pool() {
        try {
            init();
            loadDrivers(driverName);
        } catch (Exception e) {

        }
    }

    //初始化所有从配置文件中读取的成员变量
    private void init() throws IOException{
        InputStream is = Pool.class.getClassLoader().getResourceAsStream(propertiesName);
        Properties prop = new Properties();
        prop.load(is);
        this.driverName = prop.getProperty("driverName");
        this.maxConnect = Integer.valueOf(prop.getProperty("maxConnect"));
        this.normalConnect = Integer.valueOf(prop.getProperty("normalConnect"));
    };

    //装载和注册所有JDBC驱动程序
    private void loadDrivers(String driverName)  {
        try {
            driver=(Driver) Class.forName(driverName).newInstance();
            DriverManager.registerDriver(driver);
        } catch (Exception e) {
            System.err.println("无法注册JDBC驱动程序:"+driverName+",错误:"+e);
        }
    }

    //创建连接池
    public static Pool getInstance() throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {
        if (instance == null) {
            synchronized (Pool.class) {
                if (instance == null) {
                     instance=(Pool)Class.forName("com.xzq.Cases.factory.Pool").newInstance();
                     instance.init();
                }
            }
        }
        return instance;
    }

    //获得一个可用的连接,如果没有则创建一个连接,且小于最大连接限制
    public abstract Connection getConnection();

    //获得一个连接,有时间限制
    public abstract Connection getConnection(long time);

    //将连接兑现返回给连接池
    public abstract void freeConnection(Connection conn);

    //返回当前空闲连接数
    public abstract int getnum();

    //返回当先的工作的连接数
    public abstract int getnumActive();

    protected synchronized void release() {
        //撤销驱动
        try {
            DriverManager.deregisterDriver(driver);
            System.out.println("撤销JDBC驱动程序" + driver.getClass().getName());
        } catch (SQLException throwables) {
            System.err.println("无法撤销JDBC驱动程序的注册:" + driver.getClass().getName());
        }
    }

}

数据库连接池实现类

package com.xzq.Cases.factory;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;

//数据库连接池管理类
@Slf4j
public final class DBConnectionPool extends Pool{
    private static final Logger LOGGER = LoggerFactory.getLogger(DBConnectionPool.class);
    private int checkedOut; //正在使用的连接数
    private Vector<Connection> freeConnections = new Vector<>();//存放产生的连接对象容器
    private String userName = null;//账户名
    private String passWord = null; //密码
    private String url = null;      //连接url
    private static int num = 0;         //空闲连接数
    private static int numActive = 0;         //当前可用的连接数
    private static DBConnectionPool pool = null; //连接池实例变量


    public static synchronized DBConnectionPool getInstance() {
        if (pool == null) {
            pool = new DBConnectionPool();
        }
        return pool;
    }

    //连接池构造函数
    private DBConnectionPool() {
        try {
            init();
            for (int i = 0; i < normalConnect; i++) {//初始normalConn个连接
                Connection conn = newConnection();
                if (conn != null) {
                    freeConnections.addElement(conn);   //往容器中添加一个连接对象
                    num++;//记录总连接数
                }
            }
            System.out.println(">>>>>>核心连接池初始化完毕,大小为" + num);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void init() throws IOException {
        InputStream is = DBConnectionPool.class.getClassLoader().getResourceAsStream(propertiesName);
        Properties prop = new Properties();
        prop.load(is);
        this.userName = prop.getProperty("userName");
        this.passWord = prop.getProperty("passWord");
        this.url = prop.getProperty("url");
        this.driverName = prop.getProperty("driverName");
        this.maxConnect=Integer.parseInt(prop.getProperty("maxConnect"));
        this.normalConnect = Integer.parseInt(prop.getProperty("normalConnect"));
    }

    //创建一个新连接
    private Connection newConnection() {
        Connection conn = null;
        try {
            if (userName == null) {
                conn = DriverManager.getConnection(url);
            }else {
                conn = DriverManager.getConnection(url, userName, passWord);
            }
            System.out.println("连接池创建一个新的连接");
        } catch (SQLException throwables) {
            System.out.println("无法创建这个的URL的连接"+url);
            return null;
        }
        return conn;
    }

    //(单例模式)获取一个可用连接
    /**
     * 获取连接的逻辑步骤
     *  1,先判断容器中是否有连接,有则从容器的第一位取,取出之后并从容器中删除,取到无效连接则剔除
     *  2,如果容器中没有连接, 判断最大连接数是否=0,为02不限制,判断当前连接数是否小于最大连接数,如果是,则创建新的连接
     * @return
     */
    @Override
    public synchronized Connection getConnection() {
        Connection conn = null;
        if (freeConnections.size() > 0) {  //还有空闲的连接
            num--;
            conn = freeConnections.firstElement();
            freeConnections.removeElement(0);
            System.out.println(">>>>>>>>>>>>从核心连接池中获取连接,当前连接池空余数: " + num);
            try {
                if (conn.isClosed()) {
                    System.out.println("从连接池中删除一个无效连接");
                    conn = getConnection();
                }
            } catch (SQLException throwables) {
                System.out.println("从连接池中删除一个无效连接");
                conn = getConnection();
            }
        } else if (maxConnect == 0 || checkedOut < maxConnect) {    //没有空闲连接且当前连接小于最大允许值,最大值为0则不限制
            conn = newConnection();
        }
        if (conn != null) { //当前连接数+1
            checkedOut++;
        }
        numActive++;

        return conn;
    }

    //获取一个连接,并加上等待时间限制,单位为毫秒
    @Override
    public synchronized Connection getConnection(long timeOut) {
        long startTime = System.currentTimeMillis();
        Connection conn;
        while ((conn = getConnection()) == null) {
            try {
                wait(timeOut);  //线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if ((System.currentTimeMillis() - startTime) >= timeOut) {
                return null;        //如果超时,则返回
            }
        }
        return conn;
    }
    
    @Override
    protected synchronized void release() {
        try {
            //将当前连接赋值到枚举中
            Enumeration<Connection> allConnections = freeConnections.elements();
            //使用循环关闭所有连接
            while (allConnections.hasMoreElements()) {
                //如果此枚举对象至少还有一个可提供的元素,则返回此枚举对象的下一个元素
                Connection connection = allConnections.nextElement();
                try{
                    connection.close();
                    num--;
                } catch (SQLException throwables) {
                    System.out.println("无法关闭连接池中的连接");
                }
            }
            freeConnections.removeAllElements();
            numActive = 0;
        }finally {
            super.release();
        }
    }

    //如果不再是用某个连接对象,可调用此方法将该对象释放到连接池
    @Override
    public synchronized void freeConnection(Connection conn) {
        freeConnections.addElement(conn);
        num++;
        checkedOut--;
        numActive--;
        notifyAll();    //解锁
        System.out.println(">>>>>>>>>归还连接到连接池,现在连接池内空闲连接数为:"+num+",活动连接为:"+numActive+",正在使用的连接为;"+checkedOut);
    }

    @Override
    public int getnum() {
        return num;
    }

    @Override
    public int getnumActive() {
        return numActive;
    }
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值