这次写数据库连接池主要想解决的还是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. IP服务正常,域名服务异常,报400 badrequest

    IP的情况下,访问接口都正常,使用域名访问,报错400 badrequest 经确认,ssl配置无问题,证书文件本身无问题 最后查出来原因,是域名格式的问题,原域名中包含_,需要修改为- 排查过程: ...

  2. 计算QPS-Sentinel限流算法

    sentinel 前方参考 计算QPS-Sentinel限流算法 https://www.cnblogs.com/yizhiamumu/p/16819497.html Sentinel 介绍与下载使用 ...

  3. sql语句去掉前面的0(前导零,零前缀)

    sql还有个stuff的函数,很强悍. 一个列的格式是单引号后面跟着4位的数字,比如'0003,'0120,'4333,我要转换成3,120,4333这样的格式,就是去掉单引号和前导的0,用以下语句就 ...

  4. ZEGO 教程 | RTC + AI 视觉的最佳实践(移动端)

    ​  ​摘要:帮助开发者在音视频场景中快速获得 AI 视觉功能 -- 美颜.滤镜.背景抠图等. 文|即构 Native SDK 开发团队 Z世代作为社会新的消费主力,追求个性.热爱新奇事物,青睐与酷炫 ...

  5. 十三,Spring Boot 中注入 Servlet,Filter,Listener

    十三,Spring Boot 中注入 Servlet,Filter,Listener @ 目录 十三,Spring Boot 中注入 Servlet,Filter,Listener 1. 基本介绍 2 ...

  6. Hadoop & Redis未授权漏洞实战——Vulfocus服务攻防

    什么是未授权访问漏洞?Hadoop & Redis靶场实战--Vulfocus服务攻防 一.介绍 未授权访问,也称为未经授权的访问或非法访问,是指在没有得到适当权限或授权的情况下,个人或系统访 ...

  7. OSG开发笔记(三十):OSG加载动力学仿真K模型文件以及测试Demo

    前言   Osg需要打开模型文件,但是遇到显示动力学仿真的K模型文件,.k文件是一种描述材料属性的文件,比如密度.弹性模量等,该模型文件不是常规中间开放格式,无法直接支持,需要自定义解析并且重建三维模 ...

  8. transaction_timeout:达到事务超时时终止会话

    功能实现背景说明 我们已经有两个参数来控制长事务:statement_timeout 和 idle_in_transaction_session_timeout.但是,如果事务执行的命令足够短且不超过 ...

  9. KSM的使用

    使能KSM KSM只会处理通过madvise系统调用显式指定的用户进程地址空间,因此用户程序想使用这个功能就必须在分配地址空间时显式地调用madvise(addr,length,MADV_MERGEA ...

  10. css实现直线拉伸

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...