对象的数量 与 连接池连接数量的问题,困扰已久。

开发环境:win2000 server + j2sdk1.4 + Tomcat5.019 + SQLServer2000

系统概况:
*系统中用到了jsp,Servlet,Tag简单标签,javaBean,通用类。
*在Tomcat中配置了一连接池,最大连接数(maxActive)限定为3个,(主要是为了方便测试)空闲时最少保持连接数(maxIdle)为1个。
*写了一个连接数据库的类,负责与数据库建立连接并返回Connection。除了产生连接的方法,还有一个关闭连接方法,代码如下:
package Panabia.db;

import javax.sql.DataSource;
import javax.naming.*;
import java.sql.*;
public class conFactory
{
private static DataSource ds=null;
private Connection con=null;

public Connection gainCon() throws NamingException,SQLException
{
if(ds==null){
synchronized(this){
if(ds==null){
Context ctx=new InitialContext();
ds=(DataSource)ctx.lookup("java:comp/env/jdbc/Panabia");
}
}
}
con=ds.getConnection();
return con;
}

public void release() throws SQLException
{ if(con!=null&&!con.isClosed()) con.close(); }
}

问题是:
在测试的时候,如果在jsp中以javaBean的形式(<jsp:useBean id="db" class="Panabia.db.conFactory" scope="session"/>)使用conFactory,连接池工作稳定,一切都很正常;空闲时连接池中的个数保持为1,最高不过3(其实也过不了3)。

但如果将这个类导入到 JSP标签 中使用时,同时SQL连接数竟然达到了5个?!但是数据库连接池最大的同时连接数被限定到 3 个,为什么能达到5个呢------更怪的是,这5个连接会一直处于 ESTABLISHED 状态,不会被释放掉。

而单独使用 javaBean 测试,最大SQL连接达到3的时候,空闲一段时间,2个连接就会被释放,只留下1个保持连接。

在JSP标签中引用连接类代码(片段):
package Panabia.tags;

import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.io.IOException;
import java.sql.*;
import javax.naming.NamingException;
import Panabia.db.conFactory; //导入连接类

public class add_company extends TagSupport{

public int doStartTag() throws JspException{

Connection con=null;
conFactory cfy=new conFactory(); //生成连接类实例 cfy
............
........
con=cfy.gainCon(); //获取连接
................
.......(略)}

*我怀疑Tomcat是不是开了 5 个连接池?
因为用到的 JSP标签 比较多,在每个标签内都是象上面那样生成 conFactory的对象 cfy,然后获取SQL连接;
每个标签生成一个cfy,那n个标签不是就生成了n个conFactory对象?
每个对象一个连接池,所以,就出现了上面所说的同时开了5个连接的现象----

----不知这样认为对否?

但使用 javaBean时不会出现这种现象,我想,应该是 scope="session" 的缘故,jsp会自动在每个JSP页面中共享同一个 conFactory对象,而

在 JSP标签 里是每个 标签 生成一个对象,于是......??

----这个问题如何解决呢?小弟弟刚刚入门,对“对象缓冲池”之类的东东还不是特别明白,还请各位DX指条明路!


数据库连接池开启一般是在JavaBeans中,或特别的架构如EJB中,不能直接放在JSP中,Jsp是多线程,数据库连接池也是多线程,所以比较搞,我认为只要采取正确的架构,错误架构导致的问题就不必研究仔细。

感谢你的分析。

因为在程序中已经多处使用了JSP标签,我现在想解决“对象共享”的问题~
当以javaBean模式使用,并设定scope="session"时,JSP会自动在各个页面中复用“同一个conFactory”对象~

那在JSP TAG标签中有没有什么办法可以实现类似的“对象复用”功能呢?如果做到这一点,这个问题就解决得差不多了。

我曾经有个想法:
写一个Helper class,在这个class中生成conFactory对象,并一直将这个对象保存---等待 jsp标签 调用(在调用之前先进行判断,如果对象为null,就立即new一个)
不过,这个“简陋”的方法好象不是特别强壮,大家有没有其它更好的方式?
PS:就是解决对象复用的问题--避免生成过多的对象。
THKS. :)

如果架构改变不太实际的话,我觉得你可以这么实现conFactory:


public class ConFactory {
private static DataSource ds = null;

static {
//加载类时初始化ds
try {
Context ctx=new InitialContext();
ds=(DataSource)ctx.lookup(
"java:comp/env/jdbc/Panabia");
} catch (...) {
// write to log

}
}

public static Connection getConnection() {
return ds.getConnection();
}

//其他需要的方法

private ConFactory(){
}
}

然后,在你的JSP Tag中
public int doStartTag() throws JspException {
Connection con = ConFactory.getConnection();

上面的代码没有进行异常的处理,可以根据需要补充完整。
希望对你有所帮助。

:)
十分感谢你的回复!

只有static的变量与方法可以直接导入使用(不生成对象),就象你所写的:
public static Connection getConnection() {
return ds.getConnection(); }

我想,用这个方法产生的Connection肯定也是 static 的吧~~~要不,系统不允许你返回这个Connection的.

所以,问题就出来了:返回的这个Connection是静态的---
按我自己的想法,这里的Connection绝对不能声明为static的~~~
因为这样做的结果就是:无论是谁,无论采用了什么方法,到了最后都不能将Connection关闭掉(因为它是静态资源)----这就违背了一些原则。

不知这样理解是否正确?
............

PK:前一段时间看了一些有关EJB的东东,感觉特别“别扭”---本来我们可以轻易的获取一个对象---而EJB偏偏绕了那么多的弯儿,穿越了若干层才到达我们想到的地方.....汗~~~~
所以,后来也就把EJB放弃了---感觉它真的太“重”了...

不知大家对EJB有什么看法,交流一下哈. ^_^


"我想,用这个方法产生的Connection肯定也是 static 的吧"
这个是错误的想法!只要ds是static就可以了,ds的内部就不要管了吧

你的想法是错误的,每次通过getConnection()方法返回的Connection并不是静态的,每次都是动态的分配一个空闲的Connection。当然了,不要忘记使用完后释放Connection,这样才能跟其他的线程共享。

多谢!
我试试看 :)