连接池的一次实验
一、前言
话说在Java开发中,连接总是是必不可少的。有数据库连接、http连接等。面试内容也会经常问起(虽然我没被面到过:)。那究竟什么是连接池呢?它有什么作用?又是怎么实现的呢?
二、什么和为什么?
常见连接的代码通常要经历建立连接、处理业务和关闭连接三个步骤。伪代码如下:
Connection cnn =null; try{ cnn = getConnection(); cnn.excute(); }finally{ cnn.close(); }
这种情况在少数并发情况下,简单实用。可一旦面临多并发情况下就显得有些不够用了。这里的瓶颈在于每次都需要创建连接和关闭连接,这种其实重复且耗时。比如mysql其实是会缓存常用的连接,达到性能优化的效果,如果应用端频繁关闭和新建连接,那其实就用不到这种优化了。如果能复用连接,预先创建连接池,使用时拿取一个,用完再归还,从而减少创建和关闭的消耗,那必然是能达到优化的效果了。而这就是为什么采用连接池的原因了。
那至于什么是连接池?那根据上面的描述不难得出,连接池必然有以下元素:1、连接集合 2、获取连接 3、释放(归还)连接。只要具备这三样基本就能称之为连接池了。不会动手的程序猿,不是一个好攻城狮。接下来就动手试试?
三、实验
本次实验就以Java的mysql连接为例,测试普通连接方式和连接池方式的性能吧。
JdbcCnnPool类:
public class JdbcCnnPool { private static final Integer poolSize = 20; private static final ReentrantLock getLock = new ReentrantLock(); private static final ReentrantLock releaseLock = new ReentrantLock(); private static final List<Connection> cnnList = new ArrayList<>(); static public Connection getConnection() throws Exception { try { getLock.lock(); if (CollectionUtils.isEmpty(cnnList)) { for (int i = 0; i < poolSize; i++) { String URL = "jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=utf-8"; String USER = "root"; String PASSWORD = "root1234"; //1.加载驱动程序 Class.forName("com.mysql.jdbc.Driver"); //2.获得数据库链接 Connection cnn = DriverManager.getConnection(URL, USER, PASSWORD); cnnList.add(cnn); } } return cnnList.remove(0); } catch (Exception e) { throw e; } finally { getLock.unlock(); } } static public void releaseConnection(Connection connection) { try { releaseLock.lock(); if (cnnList.size() <= poolSize) { cnnList.add(connection); } } catch (Exception e) { } finally { releaseLock.unlock(); } } }
测试类:
public class ConnectionTest { @Test public void connectionTest() throws Exception { int num = 100; newConnectionTest(num); connectionPoolTest(num); } private void newConnectionTest(int num) throws Exception { Long startTime = System.currentTimeMillis(); for (int i = 0; i < num; i++) { String URL = "jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=utf-8"; String USER = "root"; String PASSWORD = "root1234"; //1.加载驱动程序 Class.forName("com.mysql.jdbc.Driver"); //2.获得数据库链接 Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); Statement st = conn.createStatement(); ResultSet rs = st.executeQuery("select * from user"); //4.处理数据库的返回结果(使用ResultSet类) while (rs.next()) { // System.out.println(rs.getString("name") + " " // + rs.getString("pwd")); } //关闭资源 rs.close(); st.close(); conn.close(); } Long endTime = System.currentTimeMillis(); System.out.println("newConnectionTest " + (endTime - startTime)); } private void connectionPoolTest(int num) throws Exception { Long startTime = System.currentTimeMillis(); for (int i = 0; i < num; i++) { Connection conn = JdbcCnnPool.getConnection(); try { Statement st = conn.createStatement(); ResultSet rs = st.executeQuery("select * from user"); while (rs.next()) { // System.out.println(rs.getString("name") + " " // + rs.getString("pwd")); } } catch (Exception e) { } finally { JdbcCnnPool.releaseConnection(conn); } } Long endTime = System.currentTimeMillis(); System.out.println("connectionPoolTest " + (endTime - startTime)); } }
实验结果:
1、100次查询(连接数据库)
正常连接执行时间:2553
连接池执行时间:322
2、1000次查询
正常连接执行时间:8376
连接池执行时间:356
3、10000次查询
正常连接执行时间:64627
连接池执行时间:1407
基本可以看出,连接池的方式的性能是正常的10倍以上,所以连接池还是很有用的。当然基本现在的连接工具基本都是采用连接池的,比如druid、c3p0、tomcat-jdbc,理解连接池的基本原理也能更好的帮助理解源码了。
四、总结
连接池是个好东西,生产上能用则用。多看轮子,多造小轮子,为了造更好的轮子!

浙公网安备 33010602011771号