这次写数据库连接池主要想解决的还是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数据库连接池的更多相关文章

  1. Java自学-JDBC 数据库连接池

    数据库连接池 与线程池类似的,数据库也有一个数据库连接池. 不过他们的实现思路是不一样的. 本章节讲解了自定义数据库连接池类:ConnectionPool,虽然不是很完善和健壮,但是足以帮助大家理解C ...

  2. JAVA之JDBC数据库连接池总结篇

    JDBC数据库连接池 一.JDBC数据库连接池的必要性 二.数据库连接池技术 三.多种开源的数据库连接池 3.1 C3P0数据库连接池 3.2 DBCP数据库连接池 3.3 Druid(德鲁伊)数据库 ...

  3. JAVA基础知识之JDBC——JDBC数据库连接池

    JDBC数据库连接池 数据库的连接和关闭是很耗费资源的操作,前面介绍的DriverManager方式获取的数据库连接,一个Connection对象就对应了一个物理数据库连接,每次操作都要打开一个连接, ...

  4. JDBC 数据库连接池

    http://www.cnblogs.com/lihuiyy/archive/2012/02/14/2351768.html JDBC 数据库连接池 小结   当对数据库的访问不是很频繁时,可以在每次 ...

  5. JDBC数据库连接池

    用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库 ...

  6. 【Java123】JDBC数据库连接池建立

    需求场景:多SQL任务多线程并行执行 解决方案:建立JDBC数据库连接池,将线程与连接一对一绑定 https://www.cnblogs.com/panxuejun/p/5920845.html ht ...

  7. Java jdbc数据库连接池总结!(转)

    1. 引言 近年来,随着Internet/Intranet建网技术的飞速发展和在世界范围内的迅速普及,计算机 应用程序已从传统的桌面应用转到Web应用.基于B/S(Browser/Server)架构的 ...

  8. Java -- JDBC 数据库连接池

    1. 原理代码示例 public class JdbcPool implements DataSource { private static LinkedList<Connection> ...

  9. java攻城狮之路--复习JDBC(数据库连接池 : C3P0、DBCP)

    复习数据库连接池 : C3P0.DBCP 1.数据库连接池技术的优点: •资源重用:      由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销.在减少系统消耗的基础上,另一方面也增 ...

  10. JDBC数据库连接池技术

    在JDBC中,获得连接或释放资源是非常消耗系统资源的两个过程,为了解决此类性能问题,通常采用连接池技术,来共享连接.这样我们就不需要每次都创建连接.释放连接了,这些操作都交给了连接池. 用池的概念来管 ...

随机推荐

  1. 使用kamailio进行分机注册及互拨

    操作系统版本:Debian 12.5_x64 kamailio版本:5.8.2 kamailio作为专业的SIP服务器,可承担注册服务器的角色.今天记录下kamailio作为注册服务器,承接分机注册, ...

  2. 深度学习学习率(Learning Rate)lr理解

    现在是2024年4月23日13:54,在看代码了,嗯,不能逃避,逃避可耻,会痛苦,看不懂多看几遍多写一下就好了,不能逃避了哈,一点一点来就是了,我还有救. 如何理解深度学习中的学习率(Learning ...

  3. ASP.NET Core – Handle Error on Web API

    前言 上一篇讲了 ASP.NET Core – Handle Error on Razor Page 这一篇继续说说 Web API 的错误处理. 主要参考 Handle errors in ASP. ...

  4. 二叉树的 Morris 中序遍历——O(1)空间复杂度

    回顾 问题陈述: 给定一棵二叉树,实现中序遍历并返回包含其中序序列的数组 例如给定下列二叉树: 我们按照左.根.右的顺序递归遍历二叉树,得到以下遍历: 最终中序遍历结果可以输出为: [3, 1, 9, ...

  5. 微信js-sdk接入原理

    1.有一个微信公众号,并获取到该公众号的AppID和AppSecret. 其中AppID是可以对外公开的,AppSecret是该公众号的密钥,是需要绝对保密的 2.向微信服务器发送一个GET请求,获取 ...

  6. SXYZ-7.4训练赛

    今天这场比赛把人心态考崩溃了,只考100分钟,四道思考和算法题,旁边大佬开局5分钟秒T1,我30分钟打了个T1暴力.┭┮﹏┭┮,呜呜~.T2,T4根据题意暴力.T3人手模拟了一下,完全没有任何思路,放 ...

  7. .Net 依赖注入深入探索,做一个DI拓展,实现一个简易灵活的 自动依赖注入框架

    一.依赖注入相关知识 1.1.依赖注入的原理和优点 依赖注入(DI),是IOC控制反转思想 的实现.由一个DI容器,去统一管理所有的服务生命周期,服务的创建.销毁.获取,都是由DI容器去处理的. 依赖 ...

  8. seaborn.lmplot详解

    官方文档 首先我们要知道,lmplot是用来绘制回归图的. 让我们来看看他的API: seaborn.lmplot(x, y, data, hue=None, col=None, row=None,  ...

  9. 2023年11月中国数据库排行榜:OPO组合持续两月,亚信、中兴闯进前十

    长夜之中蓄力待,势如破晓初光披. 2023年11月的 墨天轮中国数据库流行度排行 火热出炉,本月共有283个数据库参与排名.本月排行榜前十名变动较大,TiDB 上升一位居第4,达梦奋勇向前重归第6,亚 ...

  10. 谈谈 keep-alive 组件,以及它们的实现原理

    keep-alive 组件的使用场景: 我们切换 2 个组件的时候,2个组件会轮流被销毁创建,但是现在需求,切换到一个组件,另一个组件不会别销毁,会保留原来的状态 :就要使用 vue 内置的组件 ke ...