话说:
前面注重简单的CURD功能的实现,今天来总结下连接池。

Why?
我们每次访问页面,页面请求被后端捕获后,后台代码访问数据库,按照我们之前代码的方式,页面每请求一次,后端就连接一次,从数据库取数据,也就是调用我们的getConn()方法。一旦用户多起来,直接会造成数据库服务器的宕机或者页面卡死状态,怎么搞定?假如类似双11那样的访问量呢…….

What?

连接池
就是用来解决以上问题的一种方案。顾名思义,连接池是个数据池子,可以存放多个连接,供用户发起请求的时候直接从池子里面取值,而不是每次都访问数据库服务器。这样的话,大大提高了效率,如果一次访问次数多余连接池初始化数量,那么就有排队机制处理,等其他用户释放资源以后,在获取连接。
常见的数据连接池技术有:c3p0 dbcp druid 等等
既然是对JDBC连接的优化和补充,所以整体连接方式大同小异。

目录


一、c3p0
二、dbcp
三、druid


一、c3p0

1、根据文档配置,连接模式和链接JDBC神似。 http://www.mchange.com/projects/c3p0/ C3P0的API: http://www.mchange.com/projects/c3p0/apidocs/index.html 导入c3p0-0.9.2.1.jar mchange-commons-java-0.2.3.4.jar
新建一个类(TestC3P0Conn)来测试:

package com.hmc.datasource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.SQLException;

/**
 * User:Meice
 * 2017/10/6
 */
public class TestC3P0Conn {
    public static void main(String[] args) {
        ComboPooledDataSource cpds = new ComboPooledDataSource();
        try {

                cpds.setDriverClass("com.mysql.jdbc.Driver");//loads the jdbc driver
                cpds.setJdbcUrl("jdbc:mysql://localhost:3306/news_db");
                cpds.setUser("root");
                cpds.setPassword("119913");
                //设置连接池初始化大小
                cpds.setInitialPoolSize(300);
                //设置连接池最大大小
                cpds.setMaxPoolSize(1000);
                long start = System.currentTimeMillis();
                for(int i=1;i<=200;i++) {
                     cpds.getConnection();
                }
                 long end = System.currentTimeMillis();
            System.out.println("共耗时:"+(end-start)+"毫秒");
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // cpds.close(); //close the connection



    }
}

同样,我们也用JDBC连接来测试做对比:

package com.hmc.datasource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * User:Meice
 * 2017/10/6
 */
public class TestCommonConn {
    public static  void main(String[] args) {
        try {
            //开始计时
            long start = System.currentTimeMillis();
            //注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //模拟很多用户连接
            for(int i=1;i<=300;i++) {
                //获取连接
                Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/news_db",
                        "root", "119913");
            }
            long end = System.currentTimeMillis();
            System.out.println("共耗时:"+(end-start)+"毫秒");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

}

总结:


上面两种连接方式种,我们改变循环次数,查看连接时间(毫秒);在连接C3P0的时候,把连接池初始化大小、连接池最大连接数量轮流作为变量,调整,观察连接时间。
发现,JDBC连接循环300次,直接报错。

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: “Too many connections”

C3P0也是一样。当然这样初步测试连接时间,不够精确,有专门的测试工具.

实际有运用呢?
1、对于连接池而言,初始化值越大,那么启动速度越慢,访问速度越快;
反之亦然。
2、实践中,我们分为开发环境和生产环境。开发环境时,初始化一般设置小一些,生产环境列?不能想当然设计,要根据业务访问量来灵活设置。
3、同样,连接池还可以用来监测访问量大小。


二、DBCP

官网学习资料:
http://commons.apache.org/proper/commons-dbcp/guide/jndi-howto.html
同样,也是需要包,导入这几个。
commons-dbcp-1.4.jar
commons-logging-1.1.1.jar
commons-pool-1.5.4.jar
代码如下:

package com.hmc.datasource;
import org.apache.commons.dbcp.BasicDataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * User:Meice
 * 2017/10/6
 */
public class TestDBCPConn {
    public static void main(String[] args) {
        BasicDataSource bds= new BasicDataSource();
        bds.setDriverClassName("com.mysql.jdbc.Driver");
        bds.setUrl("jdbc:mysql://localhost:3306/news_db");
        bds.setUsername("root");
        bds.setPassword("119913");
        bds.setInitialSize(300);
        long start = System.currentTimeMillis();

        try {

            for(int i=1;i<=200;i++) {
               Connection conn = bds.getConnection();
               conn.close();
            }
            long end = System.currentTimeMillis();
            System.out.println("共耗时:"+(end-start)+"毫秒");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}

我们可以反复调整循环次数,来对比运行效率。因为我们这个是单线程,测试不是很有意义。其实最贴切的应该用多线程来实现并发访问,这样测算连接效率最好。

测试了下,当然当做玩玩啦。

Java Hikari连接池数据写入 javaweb连接池_Java Hikari连接池数据写入

网上有专业的对比,大家可以参考,那个有意义,笔者这个只是小打小闹,单线程的。

https://github.com/alibaba/druid/wiki/linux-benchmark

三、druid

参考链接
http://www.iteye.com/magazines/90
API:http://static.druid.io/api/0.10.1/
包:druid-1.0.9.jar
更多详细内容可以参考:


Java Hikari连接池数据写入 javaweb连接池_bc_02

这里温习一下之前的properties
我们在src目录下新建一个druid.properties的文件,做配

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/news_db
user=root
password=119913

写一个类:JavaDruidConn

package com.hmc.datasource;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.alibaba.druid.util.DruidDataSourceUtils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * User:Meice
 * 2017/10/6
 */
public class TestDruidConn {
    DruidDataSource dds = null;
    //获取配置数据源,封装为一个方法
    public DruidDataSource getDataSource() throws Exception {
        //以下代码加载配置文件,不在赘述
        Properties pro = new Properties();
        InputStream is = this.getClass().getClassLoader().getResourceAsStream("druid.properties");
        pro.load(is);
       String user =  pro.getProperty("url");
       System.out.println(user);
        dds = (DruidDataSource) DruidDataSourceFactory.createDataSource(pro);

        return  dds;
    }
    //获取连接方法
    public DruidPooledConnection getDruidPooledConnection(DruidDataSource dds ) throws SQLException {
        dds.setAccessToUnderlyingConnectionAllowed(true);
        DruidPooledConnection dpc = dds.getConnection();
        return  dpc;
    }

    public static void main(String[] args){
        try {
            //测试连接
         TestDruidConn tdc =   new TestDruidConn();
         DruidDataSource dds = tdc.getDataSource();
            Connection conn = tdc.getDruidPooledConnection(dds);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

不过,测试有问题。暂未找到答案,所以druid测试仅仅作为自己的一个测试记录。