Java数据库连接池原理与简易实现

1、什么是数据库连接池

    我们现在在开发中一定都会用到数据库,为了提高我们的系统的访问速度,数据库优化是一个有效的途径。我们现在开发中使用数据库一般都要经历以下的四个步骤:(1)加载数据库的驱动类,(2)建立数据库连接,(3)进行数据操作,(4)关闭数据库连接;在这四步中建立数据库连接是一个比较耗时的操作,如果每次有新的操作数据库的需求都去重新建立数据库连接必然要耗费一部分时间,拖慢系统的访问速度;在这种情况下我们就需要数据库连接池,预先创建好一定数量的数据库连接,等我们现需要使用时直接从其中拿已经创建好了尚未使用的的数据库连接,这样就可以节省掉一部分时间,加快系统的访问速度,保存这些预先创建的一定数量的数据库连接的容器称之为数据库连接池。

2、现有的常用数据库连接池

    (1)DBCP数据库连接池

    (2)C3P0数据库连接池

3、数据库连接池原理

    数据库连接池通过预先创建一定数量的空闲的数据库连接,在需要数据库连接时直接从其中获取,而不要去重新创建而节省一定的时间。

    数据库连接池的连接有连个属性,一个是本数据库的真正的连接对象,一个是标志本连接是否是空闲的标志;当数据库连接池被初始化的时候,会去创建一定数       量(一般在配置文件中配置)的数据库连接,并且这些连接都是处于空闲状态的,当需要数据库连接时,直接从数据库连接池中获取已经创建并且空闲的数据库连               接  并将其致为非空闲状态,如果数据库连接池中没有了空闲的连接,则去看数据库连接池连接数量是否以达到最大值(一般在配置文件中配置),如果没有达到最            大 值则再去创建一定数量的空闲连接;当连接使用完毕后,并不真正的关闭连接,而是将连接的状态重新致为空闲。从而达到连接重复使用的效果,节省时间。

4、简易数据库连接池的实现

  (1)、创建数据库连接池的对象,对象包括真正的数据库连接池对象和是否可用的标志。

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 数据库连接池对象
 */
public class SimplePoolEntity {

    //真正的数据库连接对象
    private Connection connection;
    //是否可用的标志,默认为true 可用
    private boolean isUsable = true;

    public Connection getConnection() {
        return connection;
    }

    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    public boolean isUsable() {
        return isUsable;
    }

    public void setUsable(boolean usable) {
        isUsable = usable;
    }

    /**
     * 数据库操作方法
     * @param sql  需要执行的sql语句
     * @return  ResultSet
     */
    public ResultSet execSql(String sql){
        ResultSet rs = null;
        try {
            Statement statement = connection.createStatement();
            rs =statement.executeQuery(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return rs;
    }
}

  (2)数据库连接池操作接口

/**
* 数据库连接池操作接口
*/
public interface SimplePoolService {
/**
* 连接池创建连接接口
* @param connCount 需要创建的连接数量
*/
void createConnection(int connCount) throws Exception;

/**
* 获取数据库连接
* @return
* @throws Exception
*/
SimplePoolEntity getConnection();
}

  (3)数据库连接池操作实现

  数据库连接池配置文件:

  

#数据库的驱动类
simple.jdbc.driver = com.mysql.jdbc.Driver
#数据库的连接url
simple.jdbc.url = jdbc:mysql://localhost:3306/test
#数据库的连接用户名
simple.jdbc.username = root
#数据库的连接密码
simpel.jdbc.password = root
#数据库连接池的初始化连接数量
simple.init.count = 10
#数据库连接池的步进数量
simple.step.count = 4
#连接池的最大数量
simple.max.count = 100

  数据库连接池的实现

/**
 * 数据库操作实现
 * 本操作中将要实现数据库连接池的初始化工作,初始化参数采用配置文件的形式来进行配置
 *
 */
public class SimplePoolServiceImpl implements SimplePoolService {

    private String jdbcDriver; // 数据库驱动
    private String jdbcUrl;  //数据库url
    private String username; //用户名
    private String password; //密码
    private Integer initCount; //初始化数量
    private Integer stepCount;  //步进数量
    private Integer maxCount; //最大数量

    private SimplePoolEntity simplePoolEntity;
    private Set<SimplePoolEntity> simplePoolEntitySet = new HashSet<>();
    /**
     * 构造方法初始化 数据库连接池
     */
    public SimplePoolServiceImpl(){
        init();
    }

    /**
     * 数据库连接池初始化
     */
    private void init(){
        //1.读取配置文件
        InputStream in =this.getClass().getClassLoader().getResourceAsStream("simpleboolconfig.properties");
        Properties properties = new Properties();
        try {
            properties.load(in);
            //设置初始化参数
            jdbcDriver = properties.getProperty("simple.jdbc.driver");
            jdbcUrl  = properties.getProperty("simple.jdbc.url");
            username  = properties.getProperty("simple.jdbc.username");
            password  = properties.getProperty("simpel.jdbc.password");
            initCount  = Integer.parseInt(properties.getProperty("simple.init.count"));
            stepCount  =Integer.parseInt( properties.getProperty("simple.step.count"));
            maxCount  =Integer.parseInt( properties.getProperty("simple.max.count"));
            //加载数据库驱动
            Driver  driver = (Driver) Class.forName(jdbcDriver).newInstance();
            //获取数据库管理对象
            DriverManager.deregisterDriver(driver);
            //初始化一定数量的连接
            createConnection(initCount);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    @Override
    public void createConnection(int connCount) throws Exception {
        //判断数据库连接池是否以达到最大连接数
        if(simplePoolEntitySet.size() + connCount > maxCount){
            throw new RuntimeException("连接池数量已到上限");
        }
        for (int i=0;i < connCount;i++){
            simplePoolEntity = new SimplePoolEntity();
            simplePoolEntity.setConnection(DriverManager.getConnection(jdbcUrl,username,password));
            simplePoolEntity.setUsable(true);
            simplePoolEntitySet.add(simplePoolEntity);
        }
    }

    @Override
    public SimplePoolEntity getConnection()  {
        try {
            SimplePoolEntity simplePoolEntity = getRealConection();
            //为空时创建新的连接
            while (simplePoolEntity == null){
                createConnection(stepCount);
                //创建连接比较耗时,建议在此处让线程延迟一定时间
                Thread.sleep(3000);
                simplePoolEntity = getRealConection();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return simplePoolEntity;
    }

    private SimplePoolEntity getRealConection() throws Exception{
        //循环连接池,获取连接
        for(SimplePoolEntity simplePoolEntity : simplePoolEntitySet){
            //判断是否为空闲
            if(simplePoolEntity.isUsable()){
                //判断连接是否有效
                if(!simplePoolEntity.getConnection().isValid(3000)){
                    //无效连接,重新创建连接替换该连接
                    Connection realConnect = DriverManager.getConnection(jdbcUrl,username,password);
                    simplePoolEntity.setConnection(realConnect);
                }
                //设置状态为不可用
                simplePoolEntity.setUsable(false);
                return simplePoolEntity;
            }
        }
        return null;
    }
}

  (4) 对外提供单例模式的数据库连接池管理对象

public class SimplePoolManger {
    //私有化构造,禁止创建
    private SimplePoolManger(){}

    //在静态内部类中实例化对象,达到懒汉单例模式
    private static class ClassLoad{
         public static SimplePoolService getSimplePoolService(){
             return  new SimplePoolServiceImpl();
         }
    }
    public static SimplePoolService getInstace(){
        return ClassLoad.getSimplePoolService();
    }
}

  

 

posted @ 2018-04-06 16:11  一条路上的咸鱼  阅读(463)  评论(0编辑  收藏  举报