在我们日常对数据库操作时存在一个问题,要为每次数据操作请求建立一个数据库连接。而每次建立连接都需要花费很多开销,如加载驱动类、注册驱动、获取连接,这样如果在短时间内连接多次,就
会耗费多余的时间(加载驱动+注册驱动)*n次;

那么就有了数据库连接池这种解决方案:

这样就节省了很多时间。而关闭数据连接与上面是一样的,就不再画了。下面是用java实现数据库连接池并分析两种方式的时间消耗:

首先是DBconnectPool.java,相当于把业务都抽象出来

package Pool;
import java.util.*;
import java.sql.*;/*** 项目名: CSDN 包名: Pool 文件名: DBconnectPool.java 创建时间: 2019年4月14日* * @author: xiatom 描述:建立数据连接池* ***/
public class DBconnectPool {// 可用数据库连接,也就是数据连接池,因为要线程安全所以使用Vectorprivate Vector<Connection> freeConnection = new Vector<>();private int maxConn;// 最大连接数private int normalConn;// 保持连接数private String pass;private String user;private String url;private int numActive = 0;// 当前活动连接数private static int num = 0;// 当前空闲连接数public DBconnectPool(String url, String user, String pass, int maxConn, int normalConn) {this.user = user;this.url = url;this.pass = pass;this.maxConn = maxConn;this.normalConn = normalConn;for (int i = 0; i < normalConn; i++) {Connection con = newConnection();if (con != null) {freeConnection.addElement(con);num++;}}}//新建连接,也就是第二张图的小格子。省去每次加载注册驱动时间private Connection newConnection() {Connection con = null;try {if (user == null)con = DriverManager.getConnection(url);elsecon = DriverManager.getConnection(url, user, pass);System.out.println("新建一个数据库链接");} catch (SQLException e) {System.out.println("新建数据库链接失败,错误:" + e);return null;}return con;}//获取当前空闲连接public int getNum() {return num;}//获取当前使用连接public int getNumActive() {return numActive;}public synchronized Connection getConnection() {Connection con = null;System.out.println(Thread.currentThread().getName() + "开始获取数据库链接");if (freeConnection.size() > 0) {num--;con = freeConnection.elementAt(0);freeConnection.removeElementAt(0);// 未考虑在数据池中已关闭的连接,若考虑需要自己加} else if (maxConn == 0 || normalConn < maxConn) {con = newConnection();}if (con != null)System.out.println(Thread.currentThread().getName() + "获取到一个数据库链接");elseSystem.out.println("得到空的数据库连接");numActive++;return con;}public synchronized void freeConnection(Connection con) {freeConnection.addElement(con);num++;numActive--;notifyAll();}//关闭所有的连接public synchronized void release() {for (Connection con : freeConnection) {try {con.close();num--;System.out.println("关闭一个数据库链接");} catch (SQLException e) {System.out.println("释放数据链接池失败");}}if (num == 0)System.out.println("释放所有链接");freeConnection.removeAllElements();numActive = 0;}
}

下面是Pool.java,实现数据库连接池:

package Pool;import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;/*** 项目名: CSDN 包名: Pool 文件名: Pool.java 创建时间: 2019年4月15日* * @author: xiatom 描述:* ***/public class Pool {private static Pool instance = null;private int maxConn = 100;private int normalConn = 10;private String password = "1023";private String user = "root";private String url = "jdbc:mysql://localhost:3306/test";private String driverName = "com.mysql.jdbc.Driver";DBconnectPool dbpool = null;Driver dbDriver = null;private Pool() {loadDriver(driverName);createPool();}private void createPool() {dbpool = new DBconnectPool(url, user, password, maxConn, normalConn);}private void loadDriver(String driver) {try {dbDriver = (Driver) Class.forName(driver).newInstance();// DriverManager.registerDriver(dbDriver);System.out.println("注册驱动类" + driver + "成功");} catch (Exception e) {System.out.println("无法注册驱动类" + driver + " 错误:" + e);}}public void freeCon(Connection con) {if (con != null) {dbpool.freeConnection(con);System.out.println("释放成功");} elseSystem.out.println("传递的是一个空连接");}public static Pool getInstance() {if (instance == null)instance = new Pool();return instance;}public Connection getCon() {return dbpool.getConnection();}public int getNum() {return dbpool.getNum();}public int getNumActive() {return dbpool.getNumActive();}public synchronized void release() {dbpool.release();try {DriverManager.registerDriver(dbDriver);System.out.println("撤销驱动成功");} catch (SQLException e) {System.out.println("撤销驱动失败");e.printStackTrace();}}
}

上面synchronized关键字是为了保证线程安全加的锁
如果没有锁:举个例子DBconnectPool类的getConnection方法

           num--;con = freeConnection.elementAt(0);
如果不加锁,则有两个线程获取连接时,都执行到上面那一步,
那么他们获取的是同一个连接,因为这时freeConnection并没有发生改变,
首元素是一样的。然后他们在都执行下面这句freeConnection.removeElementAt(0);
就会导致两个线程用的同一个连接,然后连接池丢失了一个链接

下面是依照此方法,建立10个数据连接耗费的时间

package Pool;import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;/**
* 项目名:      CSDN
* 包名:       Pool
* 文件名:      MutiThreadTest.java
* 创建时间: 2019年4月15日
*
* @author: xiatom
* 描述:
*
*
**/
public class ThreadTest implements Runnable{static Pool pool = null;public void test() {}@Overridepublic void run() {Connection con = pool.getCon();System.out.println("剩余"+pool.getNum()+"个可用连接");}public static void main(String[] args) {pool = Pool.getInstance();ThreadTest tt = new ThreadTest();Thread t[] = new Thread[10];long start = System.currentTimeMillis();for(int i=0;i<10;i++) {new Thread(tt,"Thread-"+(i+1)).start();}while(pool.getNum()!=0) {}    try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("使用时间:"+(System.currentTimeMillis()-start));}
}



由于我为了等所有线程结束所以多用了1毫秒去等待,所以实际使用时间为3毫秒左右。

下面是常规方法,建立数据连接:

import java.sql.*;
public class Connect {private Connection connection;Connect() {try {Class.forName("com.mysql.jdbc.Driver");String url = "jdbc:mysql://localhost:3306/test";this.connection = DriverManager.getConnection(url,"root","1023");} catch (ClassNotFoundException | SQLException e) {e.printStackTrace();}}public Connection getCon() {return this.connection;}
}

测试类

import java.sql.*;
public class Main {public static void main(String[] args) throws SQLException {long start = System.currentTimeMillis();for(int i=0;i<10;i++) {new Connect().getCon();}long end = System.currentTimeMillis()-start;System.out.println("消耗时间:"+end);}
}


差距就很明显了。

转载于:https://www.cnblogs.com/xiatom/p/10784849.html

数据库连接池,实现及分析相关推荐

  1. Spring事务管理 | 数据库连接池流程原理分析

  2. 传统方式连接数据库的弊端和数据库连接池原理

    本次博客带领大家学习传统方式连接数据库的弊端和数据库连接池原理. 传统获取Connection问题分析 传统的JDBC数据库连接使用 DriverManager 来获取,每次向数据库建立连接的时候都要 ...

  3. 主流Java数据库连接池分析(C3P0,DBCP,TomcatPool,BoneCP,Druid)

    http://developer.51cto.com/art/201807/579402.htm 主流数据库连接池 常用的主流开源数据库连接池有C3P0.DBCP.Tomcat Jdbc Pool.B ...

  4. 线上问题分析系列:数据库连接池内存泄漏问题的分析和解决方案

    前言 本文来自好朋友彪哥整理,实际的生产问题分析,绝对干货~ 一.问题描述 上周五晚上主营出现部分设备掉线,经过查看日志发现是由于缓存系统出现长时间gc导致的.这里的gc日志的特点是: 1.gc时间都 ...

  5. weblogic连接池不释放问题解决_数据库连接池引起的FullGC问题,看我如何一步步排查、分析、解决...

    作者:sneak 链接https://juejin.im/post/5ef800636fb9a07e66233884 来源:掘金 问题现象 在某个工作日,突然收到线上的服务告警,有大量的请求延时产生, ...

  6. hikaricp 连接池分析_数据库连接池终于搞对了,这次直接从100ms优化到3ms!

    我在研究HikariCP(一个数据库连接池)时无意间在HikariCP的Github wiki上看到了一篇文章(即前面给出的链接),这篇文章有力地消除了我一直以来的疑虑,看完之后感觉神清气爽.故在此做 ...

  7. 源码解析Spring Boot2默认数据库连接池HikariCP(高性能原因分析)

    现在市面上的数据库连接池非常多,其中HikariCP被Sping Boot2选中为默认的数据库连接池,且体积仅有152kb 为何选择HikariCP? 高性能,可以PK掉其它所有连接池,这个原因就足够 ...

  8. gc问题mysql连接池_数据库连接池引起的FullGC问题,看我如何一步步排查、分析、解决...

    问题现象 在某个工作日,突然收到线上的服务告警,有大量的请求延时产生,查看线上服务发现基本上都是获取数据库连接超时,而且影响时间只有3~4秒钟,服务又恢复了正常.隔了几分钟之后,又出现了大量的告警,还 ...

  9. jsp获取连接池的实时连接数_数据库连接池原理分析及模拟实现

    数据库访问 访问数据库主要有以下几个步骤: 加载数据库驱动 创建数据库连接 执行访问操作并处理执行结果 关闭连接,释放资源 在每一次请求数据库都要经历上述过程,创建连接和释放资源也都是些重复性的动作, ...

最新文章

  1. java delete 和deleteOnExit 的区别
  2. 一文看懂人脸识别技术发展脉络
  3. C# 多线程 线程池(ThreadPool) 2 如何控制线程池?
  4. 水平仪算公式计算机,水平仪的使用方法和计算
  5. 灰鸽子门徒自曝抓肉鸡内幕
  6. Visual Studio 2019 Community 离线注册教程
  7. 非常规应用之PNP三级管倒置使用
  8. docker使用国内加速器的正确姿势
  9. cad阀门插件lisp_cad lisp程序中看不出怎么输入命令
  10. python爬虫系列——拉勾网
  11. Visual Studio 各个版本之间的功能比较
  12. 被“淘宝”的章文嵩西邮之行
  13. 新浪微博模拟登陆并发文
  14. FSM——squirrel状态机使用
  15. 《博客园精华集---CLR/C#分册》第三轮筛选结果 转载
  16. Axie 所有技能名称及描述
  17. 如何分析常见的语音芯片故障?
  18. 着急借壳上市,居然之家被逼急了?
  19. golang 设置 http response 响应头与坑
  20. 矩阵开关多路耦合器性能参数解读

热门文章

  1. 20155204 2016-2017-2 《Java程序设计》第3周学习总结
  2. Android开发学习笔记:WebView 一
  3. php-fpm – 配置详解
  4. 用Zend Stuido 的WSDL编辑器
  5. 如何查找僵尸进程并Kill之,杀不掉的要查看父进程并杀之
  6. Apache HTTP Server Version 2.2 文档中文版
  7. FAIL - Deployed application at context path / but context failed to start
  8. 【FFmpeg】AVOutputFormat/AVInputFormat 成员变量 flags 总结
  9. 【Android】adb命令总结
  10. 【linux】Matchbox(一):启动脚本