当前位置: 首页 > 编程日记 > 正文

数据库连接池,实现及分析

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

相关文章:

BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )

考虑cdq分治, 对于[l, r)递归[l, m), [m, r); 然后计算[l, m)的操作对[m, r)中询问的影响就可以了. 具体就是差分答案排序离散化然后树状数组维护.操作数为M的话时间复杂度大概是O(M(logM)^2)-----------------------------------------------------------------------#include…

iOS开发之绝对布局和相对布局(屏幕适配)

在IOS的UI设计中也有绝对定位和相对定位&#xff0c;和我们的web前端的绝对定位和相对定位有所不同但又有相似之处。下面会结合两个小demo来学习一下我们IOS开发中UI的绝对定位和相对定位。在前面的博客中所用到的UI事例用的全是绝对定位&#xff0c;用我们Storyboard拖拽出来的…

设计模式5-抽象工厂模式

package DesignPattern;public class AbstractFactory {public static class Dough{}public static class Sauce{}public static class Veggies{}public static class Cheese{}public static class Pepperoni{}public static class Clams{}//披萨public static abstract class …

wp打印输出日志

System.Diagnostics.Debug.WriteLine(String); 转载于:https://www.cnblogs.com/songtzu/archive/2012/07/26/2609678.html

Element-ui表格选中回显

先瞄一下&#xff0c;是不是你要的效果 然后&#xff0c;废话不多说&#xff0c;直接上代码啦 1 <template>2 <div class>3 <div class"projectData">4 <el-table :data"tableData2" ref"multipleTable" :show…

iOS开发者帐号申请指南

如果你是一个开发团队&#xff0c;在你打算掏腰包购买iOS开发者授权之前&#xff0c;最好先问一下你的同事&#xff0c;是否已经有人获得了开发许可&#xff0c;因为一个开发许可一年内最多可以授权给111个设备来开发测试。如果你没有授权许可可以借用&#xff0c;或者你打算最…

Redis的KEYS命令引起宕机事件

摘要&#xff1a; 使用 Redis 的开发者必看&#xff0c;吸取教训啊&#xff01; 原文&#xff1a;Redis 的 KEYS 命令引起 RDS 数据库雪崩&#xff0c;RDS 发生两次宕机&#xff0c;造成几百万的资金损失作者&#xff1a;陈浩翔Fundebug经授权转载&#xff0c;版权归原作者所有…

GridView的编辑,更新,取消,删除等功能演示

GridView的编辑,更新,取消,删除等功能演示 这是一个GridView应用的视频&#xff0c;内容很透彻的讲解了GridView的很多实用的技巧。 下载地址&#xff1a;http://download.cnblogs.com/insus/ASPDOTNET/GridViewEditUpdateCancelDelete.rar posted on 2015-12-15 09:20 代码养家…

mac 使用homebrew 安装mysql

1. 安装homebrew ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)" brew update 2.安装mysql brew install mysql 3.设置 MySQL 用户以及数据存放地址&#xff0c;下载的mysql的mysql_install_db文件中的路径有错误 需要重新设置一下文件路径&…

触控(Touch) 、 布局(Layout)

1 使用触控实现一个简易的画板 1.1 问题 触控&#xff08;Touch&#xff09;是一个UITouch类型的对象&#xff0c;当用户触摸了屏幕上的视图时自动被创建&#xff0c;通常使用触控实现绘图、涂鸦、手写等功能。本案例使用触控实现一个简易的画板&#xff0c;可以在画板上勾画出…

fail-fast和fail-safe的介绍和区别

2019独角兽企业重金招聘Python工程师标准>>> fail-fast和fail-safe 前言 前段时间公司招的实习生在使用迭代器遍历的时候,对集合内容进行了修改,从而抛出ConcurrentModificationException. 然后给他讲解之余也整理了这一篇文章. fail-fast ( 快速失败 ) 在使用迭代器…

hdu 4311 Meeting point-1

http://acm.hdu.edu.cn/showproblem.php?pid4311 思维呀 亲 你想到就可以做出来 想不到就做不出了 什么都不说了 上代码 不知道为什么 在hdu 上 long long 和 int 相乘就让我错 #include<iostream> #include<cstdio> #include<algorithm> #include<c…

Spring Boot 整合Pagehelper(为什么PageHelper分页不生效)

引入包https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter/1.2.10 <!--分页--><!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter --><dependency><groupId>com…

关于javascript的keycode

javascript event对象的具体功能是 event对象只在事件发生的过程中才有效&#xff08;比如鼠标点击&#xff0c;键盘按下等&#xff09;。event对象用以表示事件的状态&#xff0c;例如触发event对象的元素&#xff08;event.srcElement&#xff09;、鼠标的位置&#xff08;ev…

SQL-54 查找排除当前最大、最小salary之后的员工的平均工资avg_salary。

题目描述 查找排除当前最大、最小salary之后的员工的平均工资avg_salary。CREATE TABLE salaries ( emp_no int(11) NOT NULL,salary int(11) NOT NULL,from_date date NOT NULL,to_date date NOT NULL,PRIMARY KEY (emp_no,from_date));输出格式:avg_salary69462.5555555556SQ…

JqGridView 1.0.0.0发布

前几个月&#xff0c;客户要求显示列表做到列锁定表头锁定列组合,但从Extjs到Jquery EasyUi&#xff0c;从Jquery Grid到Telerik等等组件&#xff0c;发现无一符合条件&#xff0c;要么只能用列锁定&#xff0c;要么只能用列组合&#xff0c;当两者结合就不行了。于是只好开始自…

Struts2--ActionContext及CleanUP Filter

1. ActionContext ActionContext是被存放在当前线程中的&#xff0c;获取ActionContext也是从ThreadLocal中获取的。所以在执行拦截器、 action和result的过程中&#xff0c;由于他们都是在一个线程中按照顺序执行的&#xff0c;所以可以可以在任意时候在ThreadLocal中获取 Act…

HTML5跳转页面并传值以及localStorage的用法

1、首先&#xff0c;你得在那个页面把数据存入localStorage中吧。这个是必须的&#xff01; localStorage.setItem("user",JSON.stringify(data.allUser)); 用localStorage的setItem方法&#xff0c;这个方法看名字都知道得差不多了吧。。。setItem把数据存入localSt…

冒泡排序_python实现冒泡排序

冒泡排序是比较经典的面试题&#xff0c; 它重复地走访过要排序的元素列&#xff0c;依次比较两个相邻的元素&#xff0c;如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换&#xff0c;也就是说该元素列已经…

30分钟内让你明白正则表达式是什么,并对它有一些基本的了解(二)

测试正则表达式 如果你不觉得正则表达式很难读写的话&#xff0c;要么你是一个搞笑的天才&#xff0c;要么&#xff0c;你不是地球人。正则表达式的语法很令人头疼&#xff0c;即使对经常使用它的人来说也是如此。由于难于读写&#xff0c;容易出错&#xff0c;所以找一种工具对…

(区间dp 或 记忆化搜素 )Brackets -- POJ -- 2955

http://poj.org/problem?id2955 Description We give the following inductive definition of a “regular brackets” sequence: the empty sequence is a regular brackets sequence,if s is a regular brackets sequence, then (s) and [s] are regular brackets sequences…

[初级]深入理解乐观锁与悲观锁

2019独角兽企业重金招聘Python工程师标准>>> 在数据库的锁机制中介绍过&#xff0c;数据库管理系统&#xff08;DBMS&#xff09;中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。 乐观并发控制(乐观锁…

Umbra 3:次世代的遮挡裁剪

原文链接&#xff1a;http://www.gamasutra.com/view/feature/164660/sponsored_feature_next_generation_.php?print1 来自 Umbra Software [在这个主办方特辑中&#xff0c;Umbra Software讨论了当前使用的大量裁剪遮挡方法的优缺点&#xff0c;并解释了它自己的自动化遮挡…

在64位机上PLSQL连oracle11g问题:SQL*Net not properly installed和ORA-12154:TNS:无法处理服务名...

今天有同事在给客户安装我们的系统时&#xff0c;出现了问题。 背景&#xff1a;同事安装如下&#xff1a; 服务器是小机&#xff0c;在小机上做的虚拟机。WIN&#xff12;&#xff10;&#xff10;&#xff13;操作系统&#xff0c;装的是&#xff16;&#xff14;位的。 数据…

ios 应用和电脑共享文件夹_堪比AirDrop,苹果 iPhone与Windows电脑互传文件的三种方式...

如果你是苹果全家桶用户&#xff0c;一定会对 「AirDrop(隔空投送)」 功能赞誉有加&#xff0c;使用 AirDrop 可以在 iPhone 与 MacBook、iPad 等设备之间快速传递照片、视频或文件。遗憾的是&#xff0c;「AirDrop 仅限苹果设备之间使用」&#xff0c;而很多小伙伴应该和小兽一…

Swift----函数 、 闭包 、 枚举 、 类和结构体 、 属性

1 数组排序 1.1 问题 本案例实现一个整型数组排序的函数&#xff0c;数组排序的规则由传递的规则函数决定。 1.2 方案 首先定义一个整型数组排序函数sortInts&#xff0c;该函数有一个整型数组类型的参数&#xff0c;该参数必须是输入输出参数inout&#xff0c;否则并不能修改数…

shell命令之---Linux文件权限

本章内容  理解Linux的安全性 解读文件权限 使用Linux组 1、Linux的安全性---/etc/passwd文件 # cat /etc/passwdroot:x:0:0:root:/root:/bin/bash/etc/passwd文件的字段包含了如下信息&#xff1a; 登录用户名 用户密码 用户账户的UID&#xff08;数字形式&#x…

失败原因_解析干洗店失败原因

在市面上我们其实也知道有的店面开张时间不长或者最终没有存活下来&#xff0c;干洗店也不例外。我们在看到各地干洗店的高额利润的同时&#xff0c;也会发现一些失败的干洗店。他们的干洗店为何难以运营下去呢?下面伊斯曼小编来在多个方面剖析一下其中的蹊跷和缘由&#xff1…

seg:NLP之正向最大匹配分词

已迁移到我新博客,阅读体验更佳seg:NLP之正向最大匹配分词 完整代码实现放在我的github上:click me 一、任务要求 实现一个基于词典与规则的汉语自动分词系统。二、技术路线 采用正向最大匹配(FMM)方法对输入的中文语句进行分词&#xff0c;具体的实现可以分为下面几个步骤&…

喷涂机器人保养应该注意的七个事项

喷涂机器人又叫喷漆机器人(spray painting robot)&#xff0c; 是可进行自动喷漆或喷涂其他涂料的工业机器人。目前市面上采用比较多的品牌有ABB、库卡、发那科等等&#xff0c;长时间的使用能加速工业机器人的老化&#xff0c;保养是延缓机器人老化的一大关键&#xff0c;那么…