问一个关于db connection和resultSet的close问题

04-02-09 jaghuang
在我的理解来说,conn.close()和rs.close()这两个function在我们每次使用完conn和rs后都有关闭的必要。在考虑到另一个问题的时候出现了一点矛盾。当一个大功能的实现需要连接很多次数据库的时候,如果每次都开一个connection的话,觉得似乎是一种浪费而且速度会慢。所以最好是在一个大功能中全部都使用一个connection,多个resultSet。那么,当open了一个connection后,自然在使用完后在最后要把它close。这个没问题,存在的问题是在多个rs.close(),如果在每个rs使用完后都关闭的话,那么意思就是在每一个使用rs实现的大功能中的小功能都要加一句rs.close(),那么这个rs.close()加在哪一层中呢?似乎只能加在使用了这个rs的逻辑层中(可以想象一下实现数据显示的某个javabean),那么,rs.close就不在最后的数据层中关闭了,这似乎不太符合mvc的概念,大家在做数据的时候,是使用怎么一种方法呢?是多次connection还是一次connection?如何实现?

windjp
2004-02-09 17:55
应该是一个connection,一个问题是,多个connection能做事务嘛?

我的思路是,在每次调用服务时开启连接,通过参数传地连接,调用结束后关闭,可以考虑和session facade模式配合

jaghuang
2004-02-09 18:04
问题是rs.close,我想知道的是这个

windjp
2004-02-09 18:46
还是不太明白你的意思,rs的关闭和mvc有什么联系呢?

rs应该是每次取得要用的数据后就关闭吧,connection则应当在事务完成之后关闭,数据的返回应当通过value object.

如果建立了session facade,则一个用例对应一次数据库连接。

jaghuang
2004-02-09 19:54
或许我是有点贪心,我希望做到的是所有连接数据的rs都只是通过一个function来得到,所以就需要考虑多种情况了。

jia2612
2004-02-09 23:38
如果RS不用嵌套使用的话,可以只开一个connection,如果是嵌套使用的话得要open多个connection,因为有些jdbc driver在单个Connection下不支持嵌套使用RS,你可以先把去要的数据找出来放到collection、hashmap、vector之类的数据集中,然后关闭rs,这样就可以在单连接下使用多个RS,而且可以嵌套

jaghuang
2004-02-10 08:38
确实,我现在考虑的做法就是这样的,放入一条sql,然后得出一个只有数据没有逻辑的vector,得到后再在外面做逻辑分析

现在考虑的问题是我是否应该使用一个共用function来获取呢?意思是说无论运行什么类型的rs,都放入同一个function(比如getData()),然后得到一个vector,再做逻辑分析;还是不需要这样一个共同function,而在每一个程序中都写一个getData()

cats_tiger
2004-02-10 10:09
我明白你的意思了,你用ResultSet在层间传送数据了。

不要这样作,如果你用EJB,建议参考DTO(或Value Object)和DAO模式。

如果不用EJB,建议使用RowSet接口。

ResultSet当然应该在数据层关闭。

cats_tiger
2004-02-10 10:12
使用Vector包装数据对象的做法有时也不可取,比较占内存的说。RowSet的实现通常采用了Cache,挺好用。

jaghuang
2004-02-10 11:14
RowSet?我去找找看,确实,传递rs不太好,所以现在要重新整理了

jaghuang
2004-02-10 13:46
能告诉我哪里可以下载cachedrowset吗?在网上找到的那个地址下不了。

cats_tiger
2004-02-10 16:39
SUN的实现:rowset.jar

yipsilon
2004-02-10 17:35
使用数据库链接池不就解决这个问题了?

ajoo
2004-02-11 11:29
传统的想法都是返回一个Set, List, Iterator之类。

这些方法实际上都要把数据从ResultSet读出来,缓存起来,即使用户也许本来只是想把这些数据用一定的格式输送到客户端而已。如果用户直接使用ResultSet,本来是可以省掉这个缓存的。

当然,也有把ResultSet直接adapt成Iterator的。但是这样一来,ResultSet和Connection的生命期就成了问题。就象jaghuang说的,什么时候rs.close()呢?

我提一个alternative,大家看看合适不合适。

与其返回一个Collection, array,不如接受一个回调函数。这样,用户可以自己决定是否缓存,如何缓存。而且,用户也不需要关心close和jdbc。

具体如下:

定义接口:

interface Row{

int getInt(String s);

int getInt(int i);

Object getObject(String s);

Object getObject(int i);

...

//所有ResultSet里面的getter。

}

这相当于一个只读的隐藏了jdbc细节的ResultSet的对应版本。用户的回调接受一个Row当作参数。

再定义回调接口:

interface RowListner{

//返回true表示继续下一行,false表示不要了。

boolean receive(Row row);

}

底层数据引擎:

void getData(RowListern l){

...

final ResultSet rs = ...;

try{

while(rs.next()){

if(!l.receive(Result2Row.adapt(rs)))

break;

}

finally{rs.close();}

...

}

Result2Row是一个把ResultSet转换到Row格式的adapter。遇到SqlException, 它把它变成一个RuntimeException或者某一个子类。具体我就不写了。

这样做的好处是,当用户不需要缓存数据的时候,节省空间。另外,即使用户需要缓存数据,他也有选择使用ArrayList, LinkedList, Hashtable等任意一种collection的自由。框架没必要去帮助用户做这个决定。

用它实现返回Vector或者Iterator不过是举手之劳:

class VectorRowListener implements RowListener{

public boolean receive(Row r){

v.add(r.getString(1));

return true;

}

private final Vector v = new Vector();

Vector getResult{return v;}

}

VectorRowListener vr = new VectorRowListener();

x.getData(vr);

Vector v = vr.getResult();

同理,我也可以不把结果缓存在数组中。比如说,我可以定制一个固定长度的数组,超过这个长度,就不再继续读了:

class ArrayRowListener implements RowListener{

public boolean receive(Row r){

arr[i++]=r.getString(1);

return i==arr.length;

}

private final String[] arr;

private int i = 0;

int getCount(){return i;}

ArrayRowListener(String[] a){this.arr=a;}

}

String[] arr = new String[200];//最多读200个

ArrayRowListener ar = new ArrayRowListener(arr);

x.getData(ar);

int recordRead = ar.getCount();

这应该可以帮助实现分页查询的功能吧?(当底层数据库不支持top语法时)

jaghuang
2004-02-12 16:51
昨天看了一下cats_tiger介绍的CachedRowSet,好是好,但却会破坏结构。就象在某论坛看到的某人发的贴:“把ResultSet直接populate到一个CachedRowSet里,然后把CachedRowSet通过request传递给jsp,在jsp里编码遍历如此做法很方便但破坏了struts风格”

反而ajoo说的方法倒似乎可行,容我看看再说。

猜你喜欢