| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 849 人关注过本帖
标题:[原创]动网论坛源代码解读及其向JSP的移植——第三章,选择数据库连接管理方 ...
取消只看楼主 加入收藏
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
 问题点数:0 回复次数:4 
[原创]动网论坛源代码解读及其向JSP的移植——第三章,选择数据库连接管理方案
通过我们前一章的分析,发现动网论坛是每一个页面最多保存一个对数据库的连接,为什么说是最多一个呢?因为这个数据库的连接是需要的时候才创建,如果有哪一个页面不需要访问数据库的话,那么这个页面就不用保存连接对象了。

大家都知道,创建数据库连接是相当耗费资源的一项操作,如果我们每一次需要查询的时候多要创建连接,性能是非常低下的,那么,对于数据库连接,我们究竟可以采取哪些管理办法呢?

1。需要时创建,这种办法我觉得是效率最为低下的了,想想看,每一次执行查询的时候都要创建连接,有时候一个页面就会查询5到6次,用大脚趾想就知道,这种方法要不得。事实上,相当多的ASP新手写程序,采用的就是这种办法。

2。服务器启动时创建一次,缓存在Application中。这种方法猛然一看还不错,不用频繁创建连接对象,不用在内存中缓存大量的对象。可是仔细一想,不行,对于数据密集型的操作,这些操作都在同一个连接上进行,那还不塞车啊?

3。每个会话开始的时候创建一次,缓存在Session中。这种方法比第2中方法要好,至少不会造成塞车。但是也不是完全没有弊病,弊病就是要浪费大量的缓存空间,比如,我有一万个用户同时在线,就需要缓存一万个连接,比较浪费内存,而且对于我们论坛来说,很多用户打开一个页面是比较快的,而阅读完它却相当花时间,我们执行一个查询只要几百微秒,而每个连接要缓存十几分钟,浪费大了吧。还有一种极端情况,如果有用户不停的开始会话结束会话,再开始会话再结束会话,不要笑,不要以为没有这种无聊的情况发生,拒绝服务攻击就是很好的例子,那么我们就需要不停的创建连接关闭连接,再创建连接再关闭连接,对服务器的负担也是相当大的。

4。每个页面创建连接,缓存在页面中,这种方法正是动网论坛采用的方法,其实,仔细一分析,这种方法还不如第三种,因为每个用户可以打开多个页面,那么,它浪费的资源更多,也更加容易造成拒绝服务攻击。

5。使用连接池。我们可以在应用开始的时候就创建十几二十个连接,缓存在Application中,每当一个查询需要执行的时候,就从这十几二十个连接里面挑选一个空闲的,进行操作,操作完后,再还回连接池中,对于内存的浪费不会太大,因为就算有一万个用户同时在线我也只需要缓存这么点连接对象,对于数据密集型的操作,我想只需要稍稍排一下队就可以等到一个空闲的连接,如果真的塞车了,我可以增加缓存的连接的数量,很容易,不是吗?

个人认为,使用连接池的方法比动网论坛使用的方法要好,欢迎大家探讨。
在向JSP移植的过程中,我将使用第5种方法管理数据库连接。
搜索更多相关主题的帖子: 网论坛 源代码 数据库 JSP 方案 
2006-06-14 20:36
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 
更正一下,第4种方法并不比第3种差
因为每一个页面一旦执行完,其中的数据就会被释放,而不是我们的浏览器开多长时间,就需要缓存多长时间。
所以,第4种方案和第3种方案各有千秋,如果用户频繁切换页面,则第3种方法好,如果用户在每一个页面上都呆很长时间的话,则动网论坛的这种方式相当占有优势。

相濡以沫,不如相忘于江湖
2006-06-14 20:36
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 

下面,我们就来写一个连接池的类用来管理数据库连接:

package javabbs;

import java.sql.*;

public class ConnectionPool {

public boolean[] arrIsBusy; //用于判断哪个连接是空闲的
public Connection[] arrConnections; //用于保存连接
private final int nMax = 15; //连接池中保存连接的最大个数
private final int nDelay = 1000; //当所有连接都忙时,等待的时间

public ConnectionPool(){
arrIsBusy = new boolean[nMax];
arrConnections = new Connection[nMax];
try{
//加载JDBC的驱动程序
Class.forName("com.mysql.jdbc.Driver").newInstance();
//初始化arrIsBusy和arrConnections
for(int i=0; i<nMax; i++){
arrIsBusy[i] = false;
arrConnections[i] = null;
arrConnections[i] = DriverManager.getConnection("jdbc:mysql://localhost/test?user=xielaosan&password=811116");
}
}catch(Exception e){
for(int i=0; i<nMax; i++){
arrIsBusy[i] = false;
if(arrConnections[i] != null){
try{
arrConnections[i].close();
}catch(Exception ex){}
arrConnections[i] = null;
}
}
}
}

/*======================================================
* 方法:getConnection()
* 作用:从连接池中间挑选一个空闲的连接返回
* 逻辑:在连接池中间搜索,如果有空闲的连接,则返回,如果所有的连接
* 正在被使用,则等待nDelay毫秒以后,再继续搜索。
======================================================*/
public Connection getConnection(){
int i;
for(i=0; i<nMax; i++){
if(arrIsBusy[i] == false){
arrIsBusy[i] = true;
return arrConnections[i];
}
}
if(i == nMax){
try{
Thread.sleep(nDelay);
return getConnection();
}catch(Exception e){
return null;
}
}
return null;
}

/*======================================================
* 方法:releaseConnection()
* 作用:将连接返回连接池
======================================================*/
public void releaseConnection(Connection con){
for(int i=0; i<nMax; i++){
if(arrConnections[i] == con){
arrIsBusy[i] = false;
return;
}
}

}
}


相濡以沫,不如相忘于江湖
2006-06-14 20:36
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 
下面写一个jsp页面来测试这个连接池

<%@ page contentType="text/html;charset=gb2312" %>
<%@ page import="javabbs.ConnectionPool" %>
<%@ page import="java.sql.*" %>
<jsp:useBean class="javabbs.ConnectionPool" id="objConnectionPool" scope="application" />
<html><head></head>
<body>
输出连接池对象:
<%=objConnectionPool%><br>
输出连接池中的每一个连接:<br>
<%
for(int i=0; i<15; i++){
%>
<%=i%>.<%=objConnectionPool.arrConnections[i]%><br>
<%
}
%>
输出连接池对象中的每个连接的状态:<br>
<%
for(int i=0; i<15; i++){
%>
<%=i%>.<%=objConnectionPool.arrIsBusy[i]%><br>
<%
}
%>
获取四个连接<br>
<%
Connection con1 = objConnectionPool.getConnection();
Connection con2 = objConnectionPool.getConnection();
Connection con3 = objConnectionPool.getConnection();
Connection con4 = objConnectionPool.getConnection();
%>
<%=con1%><br>
<%=con2%><br>
<%=con3%><br>
<%=con4%><br>
显示连接池的状态<br>
<%
for(int i=0; i<15; i++){
%>
<%=i%>.<%=objConnectionPool.arrIsBusy[i]%><br>
<%
}
%>
释放一个连接<br>
<%
objConnectionPool.releaseConnection(con2);
con2 = null;
%>
显示连接池的状态<br>
<%
for(int i=0; i<15; i++){
%>
<%=i%>.<%=objConnectionPool.arrIsBusy[i]%><br>
<%
}
%>
释放所有连接<br>
<%
objConnectionPool.releaseConnection(con1);
con1 = null;
objConnectionPool.releaseConnection(con3);
con3 = null;
objConnectionPool.releaseConnection(con4);
con4 = null;
%>
显示连接池的状态<br>
<%
for(int i=0; i<15; i++){
%>
<%=i%>.<%=objConnectionPool.arrIsBusy[i]%><br>
<%
}
%>

请注意,这里使用了
<jsp:useBean class="javabbs.ConnectionPool" id="objConnectionPool" scope="application" />
这一句来保证该连接池对象在整个application范围内只有一个

相濡以沫,不如相忘于江湖
2006-06-14 20:37
京山游侠
Rank: 1
等 级:新手上路
帖 子:96
专家分:0
注 册:2006-2-12
收藏
得分:0 
以上页面输出的结果如下:

输出连接池对象: javabbs.ConnectionPool@11c2b67
输出连接池中的每一个连接:
0.com.mysql.jdbc.Connection@659db7
1.com.mysql.jdbc.Connection@1556d12
2.com.mysql.jdbc.Connection@16be68f
3.com.mysql.jdbc.Connection@edf389
4.com.mysql.jdbc.Connection@fced4
5.com.mysql.jdbc.Connection@1d3cdaa
6.com.mysql.jdbc.Connection@6355dc
7.com.mysql.jdbc.Connection@19a029e
8.com.mysql.jdbc.Connection@21e554
9.com.mysql.jdbc.Connection@15718f2
10.com.mysql.jdbc.Connection@126f827
11.com.mysql.jdbc.Connection@16dfa45
12.com.mysql.jdbc.Connection@149eb9f
13.com.mysql.jdbc.Connection@c3014
14.com.mysql.jdbc.Connection@289d2e
输出连接池对象中的每个连接的状态:
0.false
1.false
2.false
3.false
4.false
5.false
6.false
7.false
8.false
9.false
10.false
11.false
12.false
13.false
14.false
获取四个连接
com.mysql.jdbc.Connection@659db7
com.mysql.jdbc.Connection@1556d12
com.mysql.jdbc.Connection@16be68f
com.mysql.jdbc.Connection@edf389
显示连接池的状态
0.true
1.true
2.true
3.true
4.false
5.false
6.false
7.false
8.false
9.false
10.false
11.false
12.false
13.false
14.false
释放一个连接
显示连接池的状态
0.true
1.false
2.true
3.true
4.false
5.false
6.false
7.false
8.false
9.false
10.false
11.false
12.false
13.false
14.false
释放所有连接
显示连接池的状态
0.false
1.false
2.false
3.false
4.false
5.false
6.false
7.false
8.false
9.false
10.false
11.false
12.false
13.false
14.false

这里需要注意的是,一定要把MySQL的JDBC驱动mysql.jar复制到Tomcat的share/lib目录中,否则就没有办法得到正确结果。我今天就是因为这个问题,浪费了几个小时的调试时间。

相濡以沫,不如相忘于江湖
2006-06-14 20:37
快速回复:[原创]动网论坛源代码解读及其向JSP的移植——第三章,选择数据库连接 ...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.027970 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved