用java实现JDBC数据库连接池
这次写数据库连接池主要想解决的还是servlet访问数据库获取数据的稳定性问题,于是便研究了一下,下面来讲一讲如何用java来写一个适合自己用的数据库连接池。这个东西大家并不陌生,通过使用数据连接池我们能够更好地控制程序和数据库之间建立的连接,减小数据库访问压力,也便于管理连接,提高了利用率和工作性能。
设计数据库连接池,个人认为应该注意以下几点:
1、能够控制连接池的大小
2、有一个统一的接口用于获得连接
3、使用后的连接要有一个接口能够接受并处理掉
4、连接池要有自我维护能力,比如说暂时提高连接池大小以应对可能的连接小高潮,或者处理多余的连接
ok,我们先确定连接池的数据结构:

1 public class SimpleConnetionPool {
2 private static LinkedList m_notUsedConnection = new LinkedList();
3 private static HashSet m_usedUsedConnection = new HashSet();
4 private static String m_url = "";
5 private static String m_user = "";
6 private static String m_password = "";
7 private static int m_maxConnect = 3;
8 static final boolean DEBUG = false;
9 static private long m_lastClearClosedConnection = System
10 .currentTimeMillis();
11 public static long CHECK_CLOSED_CONNECTION_TIME = 5000; // 5秒
12 }

然后我们看看数据库连接池的核心部分,首先是清除连接池中多余的连接。我们每隔一段时间就对连接池中的所有连接进行检查,第一轮循环判断这些链接是否已经关闭,如果关闭了则直接移除它们,第二轮循环则是根据目前规定的最大数量裁撤空闲连接。

1 private static void clearClosedConnection() {
2 long time = System.currentTimeMillis();
3
4 // 时间不合理,没有必要检查
5 if (time < m_lastClearClosedConnection) {
6 time = m_lastClearClosedConnection;
7 return;
8 }
9
10 // 时间太短,没有必要检查
11 if (time - m_lastClearClosedConnection < CHECK_CLOSED_CONNECTION_TIME) {
12 return;
13 }
14
15 m_lastClearClosedConnection = time;
16
17 // 开始检查没有使用的Connection
18 Iterator iterator = m_notUsedConnection.iterator();
19 while (iterator.hasNext()) {
20 Connection con = (Connection) iterator.next();
21
22 try {
23 if (con.isClosed()) {
24 iterator.remove();
25 }
26 } catch (SQLException e) {
27 iterator.remove();
28
29 if (DEBUG) {
30 System.out.println("问题连接已断开");
31 }
32 }
33 }
34
35 // 清除多余的Connection
36 int decrease = getDecreasingConnectionCount();
37
38 while (decrease > 0 && m_notUsedConnection.size() > 0) {
39 Connection con = (Connection) m_notUsedConnection.removeFirst();
40
41 try {
42 con.close();
43 } catch (SQLException e) {
44
45 }
46
47 decrease--;
48 }
49 }

接下来我们看一下申请一个新的连接是如何进行的,首先我们先调用之前的清理器来清除多余的连接和无法使用的连接,之后在空闲连接中寻找是否有可是的连接,如果有符合的则直接分配出去,但是要是没找到的话该怎么办呢?
这时候我们就需要建立新的连接来提供了,建立新的连接后我们将其中一个分配出去,剩下的加入到空闲连接中去等待分配就可以了。

1 public static synchronized Connection getConnection() {
2 // 关闭清除多余的连接
3 clearClosedConnection();
4
5 // 输出当前总连接数
6 if(DEBUG)
7 System.out.println("当前总连接数:" + getConnectionCount());
8
9 // 寻找空闲的连接
10 while (m_notUsedConnection.size() > 0) {
11 try {
12 Connection con = (Connection) m_notUsedConnection.removeFirst();
13
14 if (con.isClosed()) {
15 continue;
16 }
17
18 m_usedUsedConnection.add(con);
19 if (DEBUG) {
20 // System.out.println("连接初始化成功");
21 }
22 return con;
23 } catch (SQLException e) {
24 }
25 }
26
27 // 没有找到,建立一些新的连接以供使用
28 int newCount = getIncreasingConnectionCount();
29 LinkedList list = new LinkedList();
30 Connection con = null;
31
32 for (int i = 0; i < newCount; i++) {
33 con = getNewConnection();
34 if (con != null) {
35 list.add(con);
36 }
37 }
38
39 // 没有成功建立连接,访问失败
40 if (list.size() == 0)
41 return null;
42
43 // 成功建立连接,使用的加入used队列,剩下的加入notUsed队列
44 con = (Connection) list.removeFirst();
45 m_usedUsedConnection.add(con);
46 m_notUsedConnection.addAll(list);
47 list.clear();
48
49 return con;
50 }

根据之前总结的我们还需要一个,就是交还连接了,这个很简单,把占用中的链接移出来放到空闲连接里就可以了~很简单吧~

1 static synchronized void pushConnectionBackToPool(Connection con) {
2 boolean exist = m_usedUsedConnection.remove(con);
3 if (exist) {
4 m_notUsedConnection.addLast(con);
5 }
6 }

这就是这个数据连接池的核心部分了,现在我们来看整套代码就容易多了,其实需要注意的就是刚才说的那些:

1 package cn.com.css.cas.jdbc;
2
3 import java.sql.Connection;
4 import java.sql.Driver;
5 import java.sql.DriverManager;
6 import java.sql.SQLException;
7 import java.util.HashSet;
8 import java.util.Iterator;
9 import java.util.LinkedList;
10
11 /**
12 * JDBC数据库连接池
13 *
14 * @author Woud
15 *
16 */
17 public class SimpleConnetionPool {
18 private static LinkedList m_notUsedConnection = new LinkedList();
19 private static HashSet m_usedUsedConnection = new HashSet();
20 private static String m_url = "";
21 private static String m_user = "";
22 private static String m_password = "";
23 private static int m_maxConnect = 3;
24 static final boolean DEBUG = false;
25 static private long m_lastClearClosedConnection = System
26 .currentTimeMillis();
27 public static long CHECK_CLOSED_CONNECTION_TIME = 5000; // 5秒
28
29 static {
30 try {
31 initDriver();
32 } catch (InstantiationException e) {
33 // TODO Auto-generated catch block
34 e.printStackTrace();
35 } catch (IllegalAccessException e) {
36 // TODO Auto-generated catch block
37 e.printStackTrace();
38 } catch (ClassNotFoundException e) {
39 // TODO Auto-generated catch block
40 e.printStackTrace();
41 }
42 }
43
44 public SimpleConnetionPool(String url, String user, String password) {
45 m_url = url;
46 m_user = user;
47 m_password = password;
48 }
49
50 private static void initDriver() throws InstantiationException,
51 IllegalAccessException, ClassNotFoundException {
52 Driver driver = null;
53
54 // 读取MySql的Driver
55 driver = (Driver) Class.forName("com.mysql.jdbc.Driver").newInstance();
56 installDriver(driver);
57
58 /*
59 * // 读取postgresql的driver driver = (Driver)
60 * Class.forName("org.postgresql.Driver").newInstance();
61 * installDriver(driver);
62 */
63
64 }
65
66 public static void installDriver(Driver driver) {
67 try {
68 DriverManager.registerDriver(driver);
69 } catch (SQLException e) {
70 // TODO Auto-generated catch block
71 e.printStackTrace();
72 }
73 }
74
75 public static synchronized Connection getConnection() {
76 // 关闭清除多余的连接
77 clearClosedConnection();
78
79 // 输出当前总连接数
80 if(DEBUG)
81 System.out.println("当前总连接数:" + getConnectionCount());
82
83 // 寻找空闲的连接
84 while (m_notUsedConnection.size() > 0) {
85 try {
86 Connection con = (Connection) m_notUsedConnection.removeFirst();
87
88 if (con.isClosed()) {
89 continue;
90 }
91
92 m_usedUsedConnection.add(con);
93 if (DEBUG) {
94 // System.out.println("连接初始化成功");
95 }
96 return con;
97 } catch (SQLException e) {
98 }
99 }
100
101 // 没有找到,建立一些新的连接以供使用
102 int newCount = getIncreasingConnectionCount();
103 LinkedList list = new LinkedList();
104 Connection con = null;
105
106 for (int i = 0; i < newCount; i++) {
107 con = getNewConnection();
108 if (con != null) {
109 list.add(con);
110 }
111 }
112
113 // 没有成功建立连接,访问失败
114 if (list.size() == 0)
115 return null;
116
117 // 成功建立连接,使用的加入used队列,剩下的加入notUsed队列
118 con = (Connection) list.removeFirst();
119 m_usedUsedConnection.add(con);
120 m_notUsedConnection.addAll(list);
121 list.clear();
122
123 return con;
124 }
125
126 public static Connection getNewConnection() {
127 try {
128 Connection con = DriverManager.getConnection(m_url, m_user,
129 m_password);
130 return con;
131 } catch (SQLException e) {
132 // TODO Auto-generated catch block
133 e.printStackTrace();
134 }
135
136 return null;
137 }
138
139 static synchronized void pushConnectionBackToPool(Connection con) {
140 boolean exist = m_usedUsedConnection.remove(con);
141 if (exist) {
142 m_notUsedConnection.addLast(con);
143 }
144 }
145
146 public static int close() {
147 int count = 0;
148
149 Iterator iterator = m_notUsedConnection.iterator();
150 while (iterator.hasNext()) {
151 try {
152 ((Connection) iterator.next()).close();
153 count++;
154 } catch (SQLException e) {
155 // TODO Auto-generated catch block
156 e.printStackTrace();
157 }
158 }
159 m_notUsedConnection.clear();
160
161 iterator = m_usedUsedConnection.iterator();
162 while (iterator.hasNext()) {
163 try {
164 ((Connection) iterator.next()).close();
165 } catch (SQLException e) {
166 // TODO Auto-generated catch block
167 e.printStackTrace();
168 }
169 }
170 m_usedUsedConnection.clear();
171
172 return count;
173 }
174
175 private static void clearClosedConnection() {
176 long time = System.currentTimeMillis();
177
178 // 时间不合理,没有必要检查
179 if (time < m_lastClearClosedConnection) {
180 time = m_lastClearClosedConnection;
181 return;
182 }
183
184 // 时间太短,没有必要检查
185 if (time - m_lastClearClosedConnection < CHECK_CLOSED_CONNECTION_TIME) {
186 return;
187 }
188
189 m_lastClearClosedConnection = time;
190
191 // 开始检查没有使用的Connection
192 Iterator iterator = m_notUsedConnection.iterator();
193 while (iterator.hasNext()) {
194 Connection con = (Connection) iterator.next();
195
196 try {
197 if (con.isClosed()) {
198 iterator.remove();
199 }
200 } catch (SQLException e) {
201 iterator.remove();
202
203 if (DEBUG) {
204 System.out.println("问题连接已断开");
205 }
206 }
207 }
208
209 // 清除多余的Connection
210 int decrease = getDecreasingConnectionCount();
211
212 while (decrease > 0 && m_notUsedConnection.size() > 0) {
213 Connection con = (Connection) m_notUsedConnection.removeFirst();
214
215 try {
216 con.close();
217 } catch (SQLException e) {
218
219 }
220
221 decrease--;
222 }
223 }
224
225 public static int getIncreasingConnectionCount() {
226 int count = 1;
227 count = getConnectionCount() / 4;
228
229 if (count < 1)
230 count = 1;
231
232 return count;
233 }
234
235 public static int getDecreasingConnectionCount() {
236 int count = 0;
237
238 if (getConnectionCount() > m_maxConnect) {
239 count = getConnectionCount() - m_maxConnect;
240 }
241
242 return count;
243 }
244
245 public static synchronized int getNotUsedConnectionCount() {
246 return m_notUsedConnection.size();
247 }
248
249 public static synchronized int getUsedConnectionCount() {
250 return m_usedUsedConnection.size();
251 }
252
253 public static synchronized int getConnectionCount() {
254 return m_notUsedConnection.size() + m_usedUsedConnection.size();
255 }
256
257 }

我们做好了这个连接池之后怎么用呢,这很简单,我们用Singleton模式做一个连接池管理器,然后对接口进行简单的封装后就可以进行使用了,管理器调用连接池的getconnection接口获得connect后和数据库建立连接,运行sql后交还connect并把结果反馈回来就可以了。
用java实现JDBC数据库连接池的更多相关文章
- Java自学-JDBC 数据库连接池
数据库连接池 与线程池类似的,数据库也有一个数据库连接池. 不过他们的实现思路是不一样的. 本章节讲解了自定义数据库连接池类:ConnectionPool,虽然不是很完善和健壮,但是足以帮助大家理解C ...
- JAVA之JDBC数据库连接池总结篇
JDBC数据库连接池 一.JDBC数据库连接池的必要性 二.数据库连接池技术 三.多种开源的数据库连接池 3.1 C3P0数据库连接池 3.2 DBCP数据库连接池 3.3 Druid(德鲁伊)数据库 ...
- JAVA基础知识之JDBC——JDBC数据库连接池
JDBC数据库连接池 数据库的连接和关闭是很耗费资源的操作,前面介绍的DriverManager方式获取的数据库连接,一个Connection对象就对应了一个物理数据库连接,每次操作都要打开一个连接, ...
- JDBC 数据库连接池
http://www.cnblogs.com/lihuiyy/archive/2012/02/14/2351768.html JDBC 数据库连接池 小结 当对数据库的访问不是很频繁时,可以在每次 ...
- JDBC数据库连接池
用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库 ...
- 【Java123】JDBC数据库连接池建立
需求场景:多SQL任务多线程并行执行 解决方案:建立JDBC数据库连接池,将线程与连接一对一绑定 https://www.cnblogs.com/panxuejun/p/5920845.html ht ...
- Java jdbc数据库连接池总结!(转)
1. 引言 近年来,随着Internet/Intranet建网技术的飞速发展和在世界范围内的迅速普及,计算机 应用程序已从传统的桌面应用转到Web应用.基于B/S(Browser/Server)架构的 ...
- Java -- JDBC 数据库连接池
1. 原理代码示例 public class JdbcPool implements DataSource { private static LinkedList<Connection> ...
- java攻城狮之路--复习JDBC(数据库连接池 : C3P0、DBCP)
复习数据库连接池 : C3P0.DBCP 1.数据库连接池技术的优点: •资源重用: 由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销.在减少系统消耗的基础上,另一方面也增 ...
- JDBC数据库连接池技术
在JDBC中,获得连接或释放资源是非常消耗系统资源的两个过程,为了解决此类性能问题,通常采用连接池技术,来共享连接.这样我们就不需要每次都创建连接.释放连接了,这些操作都交给了连接池. 用池的概念来管 ...
随机推荐
- Android Adapter 添加数据,忽然变成倒序
忽然出现的问题,最后发现:因为RecyclerView 调用 setLayoutManager方法时,最后一个参数是否显示分割线为true 改为false即可
- Session——基本使用
Session Session 原理 Session 使用细节
- 【QT性能优化】QT性能优化之QT6框架高性能网络编程框架实现百万TCP长连接网络服务器:QT是否适合做高性能网络应用?补天云这个视频告诉你在大厂Linux云服务器上的实测结果
QT性能优化之QT6框架高性能网络编程框架实现百万TCP长连接网络服务器 Ø 简介 本文作者编写了一套基于QT的TCP网络服务器程序和基于QT的TCP客户端程序,在某大厂的云服务器上进行了C1000K ...
- 2024-09-21:用go语言,给定一个字符串 s,字符串中的每个字符要么是小写字母,要么是问号‘?‘。对于一个仅包含小写字母的字符串t,我们定义cost(i)为在t的前i个字符中与t[i]相同的字
2024-09-21:用go语言,给定一个字符串 s,字符串中的每个字符要么是小写字母,要么是问号'?'.对于一个仅包含小写字母的字符串t,我们定义cost(i)为在t的前i个字符中与t[i]相同的字 ...
- 第24天:安全开发-PHP应用&文件管理模块&显示上传&黑白名单类型过滤&访问控制
#文件管理模块-上传-过滤机制 1.无过滤机制 2.黑名单过滤机制 3.白名单过滤机制 4.文件类型过滤机制 $_FILES:PHP中一个预定义的超全局变量,用于在上传文件时从客户端接收文件,并将其保 ...
- TS体操类型学习记录
Easy 1. Easy - 4 - Pick 从类型 T 中选出符合 K 的属性,构造一个新的类型 type MyPick<T, K extends keyof T> = { [key ...
- uprobe
本章的我们来学习uprobe ,顾名思义,相对于内核函数/地址的监控,主要用于用户态函数/地址的监控.听起来是不是有点神奇,内核怎么监控用户态函数的调用呢?本章的内容包括: 如何使用uprobe 内核 ...
- OOP的核心思想
1. 封装 既是信息封装,把一些信息进行封装成对象,只保留部分接口和方法与外部联系,能有效避免程序间相互依赖,实现代码模块间松藕合 : 2. 继承 子类自动继承父类的属性和方法,继承实现了代码的重用性 ...
- ADO.NET 事务 transaction
事务回滚:
- Vue中mixins(混入)的介绍和使用
为什么引进 mixins 随着项目的开发,组件越来越多 ,这就导致了在各个组件中需要编写功能相同的代码段,重复地定义这些相同的属性和方法,导致代码地冗余,还不利于后期代码的维护 混入mixins 的创 ...