数据库链接池技术详解

前言

今天来说一下数据库链接池技术.其实这个名词也就是听起来高大上一点,实际上并非很复杂的内容,相信在个人讲解下,而且本身实际的将代码写一遍以后,可以对这项技术有较为深入的理解.废话很少说,开始讲解.java

数据库链接池技术概述

所谓的数据库链接池技术,就是用来分配,管理,释放数据库链接的.你也许会问,好像我直接用JDBC也可以实现这些功能吧. 嗯,你说的没错,JDBC确实也能够,可是,你记不记得,咱们使用JDBC技术的时候,每次用完了,是否是都会将链接关闭;等到下一次再用的时候,是否是都得将数据库链接再打开? 实际上,数据库连接资源是十分宝贵的,咱们在小型的项目中还看不出来,在高并发的项目中,你会发现,这样频繁的打开和关闭数据库连接是对服务器的一种摧残,十分影响效率. 那么,数据库链接池是如何作的呢? 实现思路是这样的:在每次有访问的时候,数据库链接池会给用户分配一个数据库链接,当用户用完了链接以后,链接池再将链接回收,放回一个链接集合中. 原理就是这样的,咱们来看一下这张图加深印象 mysql

这里写图片描述
这样你可能仍是不太清楚,并且,数据库链接池要考虑的东西要比上面说的更复杂,不过不要惧怕,我经过实际的代码来帮你理解一下. 备注:下面的代码是本身实现一个简单的数据库链接池,着重了解数据库链接池的原理.

本身实现一个数据库链接池

注意:下面的代码我是分块讲解的,你一个个粘贴下来,最后确定也是能运行的,为了方便,我会在讲完以后,给出完整的实现代码.sql

  • 定义初始化链接数目,最大链接数以及当前已经链接的数目 一开始,当数据库链接池启动的时候,为了实现上面的需求,咱们确定是要先给出几个已经完成的链接的,这样用户访问的时候就能直接拿到了;此外,当某一段时间的访问用户超过我定义的链接池中的链接个数,确定是要额外新建链接给用户使用;固然,这个新建的链接确定是不能无限制的,不然仍是会很影响效率的,因此,咱们还要定义最大的链接数.
private final int init_count = 3; //初始化连接数目
private final int max_count = 6; //最大链接数
private int current_count = 0; //到当前链接数
复制代码
  • 那么,咱们一开始新建的链接池要放在哪里供用户使用呢?确定是要建立一个链接集合的,这样的操做比较方便.至于为何要使用LinkedList这样一个集合,一会就会介绍的.
private LinkedList<Connection> pool = new LinkedList<Connection>();
复制代码
  • 刚才说了,一开始咱们确定是要初始化链接给用户使用的,那么,就须要在链接池启动的时候就新建必定数量的连接.分析后发现,放在构造函数中初始化连接是最好不过的了,最后再将链接放在连接集合中.
//构造函数,初始化连接放入链接池
 public MyPool() {
     for (int i=0;i<init_count;i++){
         //记录当前链接数
         current_count++;
         //createConnection是自定义的建立连接函数.
         Connection connection = createConnection();
         pool.addLast(connection);
     }
 }
复制代码
  • 建立一个新的链接,这个就没啥好说的了,毕竟你要的连接都是从这来的.
public Connection createConnection() {
	Class.forName("com.mysql.jdbc.Driver");
	Connection connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/keyan","root","root");
	return connection;
}
复制代码
  • 获取连接 当用户来访问的时候,咱们确定是要给用户一个链接的,若是池中没有链接了(全部链接均被占用),那么就要建立新的链接,使用createConnection()函数,固然,这个链接的个数确定是不能超过最大链接数的.若是不知足这两个条件,那么直接抛出异常.
public Connection getConnection() {
     if (pool.size() > 0){
         //removeFirst删除第一个而且返回
         //如今你必定看懂了我说的为什要用LinkedList了吧,由于下面的这个
         //removeFirst()方法会将集合中的第一个元素删除,可是还会返回第一个元素
         //这样就省去了咱们不少没必要要的麻烦
         return pool.removeFirst();
     }
     if (current_count < max_count){
         //记录当前使用的链接数
         current_count++;
         //建立连接
         return createConnection();
     }
     throw new RuntimeException("当前连接已经达到最大链接数");
}
复制代码
  • 释放资源 当用户使用完了链接以后,咱们要作的并非关闭链接,而是将链接从新放入资源池LinkedList之中,这样就省去了一遍又一遍的链接关闭.这个就是链接池的核心内容.是否是很简单?
public void releaseConnection(Connection connection){
    if (pool.size() < init_count){
        pool.addLast(connection);
        current_count--;
    }else {
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
复制代码

整个的实现过程就是这样的,下面我把所有的代码贴出来,方便你们学习.数据库

//单元测试
@Test
public class MyPool {
    private final int init_count = 3; //初始化连接数目
    private final int max_count = 6; //最大
    private int current_count = 0; //到当前链接数
    //链接池,用来存放初始化连接
    private LinkedList<Connection> pool = new LinkedList<Connection>();

    //构造函数,初始化连接放入链接池
    public MyPool() {
        for (int i=0;i<init_count;i++){
            //记录当前链接数
            current_count++;
            Connection connection = createConnection();
            pool.addLast(connection);
        }
    }

    //建立新的链接
    public Connection createConnection() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/keyan","root","root");
            return connection;
        }catch (Exception e){
            System.out.println("数据库连接异常");
            throw new RuntimeException();
        }
    }

    //获取连接
    public Connection getConnection() {
        if (pool.size() > 0){
            //removeFirst删除第一个而且返回
            return pool.removeFirst();
        }
        if (current_count < max_count){
            //记录当前使用的链接数
            current_count++;
            //建立连接
            return createConnection();
        }
        throw new RuntimeException("当前连接已经达到最大链接数");
    }

    //释放连接
    public void releaseConnection(Connection connection){
        if (pool.size() < init_count){
            pool.addLast(connection);
            current_count--;
        }else {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
复制代码

本身跑了一遍代码以后,你是否是发现原来看起来很复杂的技术,并不像咱们想得那样? 好了,介绍完了基本的数据库链接池技术原理以后,咱们就要介绍两个开源的优秀的数据链接池技术. 其实,真正的数据库链接池要考虑的东西比咱们刚才写的这玩意复杂,现阶段不须要咱们写这样复杂的东西,不过若是你感兴趣的话,能够看看数据库链接池的源代码--没错,这两个链接池都是开源的.OK,接下来就开始吧!tomcat

优秀的数据库链接池

首先,sun公司规定,链接池技术需实现javax.sql.DataSource接口,也就是说,若是你要本身实现数据库链接池,那么就必须实现这个接口.是否是很牛比的样子,实际上,做为标准制定方,sun公司仍是有不少要求的,这是做为标准制定者的权利,因此,企业或者国家每每会对一些关键技术标准的制定打得头破血流.额,扯远了...bash

DBPC

其实,你可能不知道,若是你的tomcat通过特殊的配置,也是能够做为数据库链接池使用的,由于tomcat内置的就是DBPC.. 想要使用DBPC,你必须导入三个jar文件:commons-dbcp2-2.2.0.jar,commons-pool2-2.5.0.jar,commons-logging-1.2.jar.我想,以你的聪明才智,想要获取这三个jar文件,必定是小菜一叠,这是一个软件开发者的必备技能--学会如何搜索. 使用起来就很是简单了.使用的方式主要有两种,一种是硬编码的方式,就是本身手动设置各类参数,另一种就是配置相应的配置文件,而后载入就好了.服务器

硬编码实现DBPC

BasicDataSource dataSource = new BasicDataSource();
//参数配置:初始化链接数,最大链接数,链接字符串,驱动,用户,密码
dataSource.setInitialSize(3);   //最大初始化连接
dataSource.setMaxTotal(6);      //最大连接
dataSource.setMaxIdle(3000);    //最大空闲时间
dataSource.setUrl("jdbc:mysql:///keyan");   //url
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("root");

//获取连接
Connection connection = dataSource.getConnection();
connection.prepareStatement("SELECT * FROM e_person").execute();
connection.close();
复制代码

使用查询的时候,只须要按照原来JDBC的操做方式就好了,这个没啥好说的,按照我上面的配置方式实现就好了,必定不要忘记导入包.微信

配置文件方式实现

//建立properties配置文件
Properties properties = new Properties();
//获取文件流
InputStream in = DBCPTest.class.getResourceAsStream("db.properties");
//加载配置文件
properties.load(in);
//建立数据源对象
BasicDataSource dataSource = BasicDataSourceFactory.createDataSource(properties);

//获取连接
Connection connection = dataSource.getConnection();
ResultSet resultSet = connection.prepareStatement("SELECT * FROM e_person").executeQuery();
while (resultSet.next()){
   System.out.println(resultSet.getString("work_name"));
}
connection.close();
复制代码

上面是基本的操做流程,下面咱们看一下这个xml文件的配置 文件db.properties并发

url=jdbc:mysql:///keyan
driverClassName=com.mysql.jdbc.Driver
username=root
password=root
initialSize=3
maxActive=6
maxIdle=3000
复制代码

特别要注意的一点是,这个配置文件必定要放在和你的这DBPC类放在同一个包下. 都完成了以后,直接用就能够了.函数

C3P0

c3p0一样是很是优秀的链接池技术,这个须要导入的文件比较少,只有一个c3p0-0.9.1.2.jar.本身去网站上找一下就行了. 使用c3p0一样是有两种方式,分别也是硬编码方式和配置文件方式.

硬编码方式

//配置相关的参数
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql:///keyan");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setUser("root");
dataSource.setPassword("root");
dataSource.setInitialPoolSize(3);
dataSource.setMaxPoolSize(6);
dataSource.setMaxIdleTime(1000);

Connection connection = dataSource.getConnection();
//sql语句
ResultSet resultSet = connection.prepareStatement("SELECT * FROM e_project").executeQuery();
while (resultSet.next()){
   System.out.println(resultSet.getString("project_name"));
}
connection.close();
复制代码

和上面同样,简单的使用一下就好了,知道如何使用就行.至于更加深层次的东西,有兴趣的话慢慢研究吧.

配置文件方式

ComboPooledDataSource dataSource = new ComboPooledDataSource();
Connection connection = dataSource.getConnection();
ResultSet resultSet = connection.prepareStatement("SELECT * FROM e_project").executeQuery();
while (resultSet.next()){
    System.out.println(resultSet.getString("project_name"));
}
connection.close();
复制代码

乍一看,你可能会问,不是配置文件方式实现吗?没错,只是这个是隐式的调用,不须要你实现,只须要新建一个ComboPooledDataSource对象就好了,默认调用xml文件,文件路径是src根目录.也就是说,你只须要将配置文件写在src目录下就好了.重点是如何写这个xml文件. 注意,文件名c3p0-config.xml,这个文件名不能改,必须是这个,文件路径必须是src根目录,不然读取不到.

<c3p0-config>
    <default-config>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">root</property>
        <property name="password">root</property>
        <property name="initialPoolSize">3</property>
        <property name="maxPoolSize">6</property>
        <property name="maxIdleTime">1000</property>
    </default-config>
</c3p0-config>
复制代码

配置文件的参数大致上用到的就这么多,固然,你也能够去找一下相关的资料,了解一下更加详细的参数意义,这些参数,我么平常使用足够了.

补充内容:数据库链接池的优势

资源重用

因为数据库链接得以重用,避免了频繁建立,释放链接引发的大量性能开销。在减小系统消耗的基础上,另外一方面也增长了系统运行环境的平稳性。

更快的系统反应速度

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

新的资源分配手段

对于多应用共享同一数据库的系统而言,可在应用层经过数据库链接池的配置,实现某一应用最大可用数据库链接数的限制,避免某一应用独占全部的数据库资源

统一的链接管理,避免数据库链接泄露:

在较为完善的数据库链接池实现中,可根据预先的占用超时设定,强制回收被占用链接,从而避免了常规数据库链接操做中可能出现的资源泄露

结语

感谢您的阅读,欢迎指正博客中存在的问题,也能够跟我联系,一块儿进步,一块儿交流!

微信公众号:进击的程序狗 邮箱:roobtyan@outlook.com 我的博客:roobtyan.cn 扫描下面的二维码关注我吧,你将收获到意想不到的东西哟…… 给你们准备了一份很是棒的JAVA的视频教程,从JAVA基础一直到JAVAWEB,还有很是强大的项目实战。 就在个人微信公众号里,回复java就可查看,免费的呦!

这里写图片描述
相关文章
相关标签/搜索