服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

查询数据库后返回iterator

既然我们把数据库访问封装起来了,那么如果查询数据库返回的是一系列结果,比如我们从数据库中得到所有人的用户名,然后在jsp页面显示出来。

这里就有一个普遍疑问,我这个javabean是返回resultset到jsp中还是collection?

我曾经有段时间图省事,直接返回resultset,然后在我的jsp页面中是大量的resultset遍历。这其实还是将数据层和显示层混淆在一起。在ejb cmp中,返回的是collection,这样偶合性降低,不用在修改数据库结构后,一直修改程序到前台jsp页面,这和以前的php asp开发方式没两样。

但是返回collection效率不是很高,因为意味着在内存中要开辟一个内存存放所有的结果。

我看了http://builder.com.com/article.jhtml?id=u00220020814r4b01.htm这篇文章后,觉得启发很大,返回iterator就可以了。

iterator也是个模式,在jive中大量使用了iterator,我以前很奇怪,为什么他没事自己写个iterator,现在知道原因了,这样节省内存,而且效率高。

看下面比较:

public list getusers() {
resultset rs = userdbquery();
list retval = new arraylist();
while (rs.next()) {
retval.add(rs.getstring(1));
}
return retval;
}
上面是个我们采取返回collection后最常用的方法,将resultset中的用户名加入list再返回,显然这很耗费内存。

使用iterator返回:
public iterator getusers() {
final resultset rs = userdbquery();
return new iterator() {
private object next;

public boolean hasnext() {
if (next == null) {
if (! rs.next()) {
return false;
}
next = rs.getstring(1);
}
return true;
}

public object next() {
if (! hasnext()) {
throw new nosuchelementexception();
}
string retval = next;
next = null;
return retval;
}

public void remove() {
throw new unsupportedoperationexception("no remove allowed");
}
}
}

这里返回的是一个内部类,其实你可以象jive那样,专门做个iterator类,这样,这里写得就不那么难看,你自己定义的iterator和collection中的iterator没有任何关系,自己定义了三个方法 hasnext(); next(); remove();这样看上去和collection的iterator是一样的。

从自己作的这个iterator类中看到,这个javabean只是做了一个指针传递作用,将调用本javabean的指针传递到resultset,这样既提高了效率,节约了内存,又降低了偶合性,这是堪称中间件典型的示范。

既然返回iterator这么好,有人经常用到一个简单的返回iterator方法:
public iterator getusers() {
resultset rs = userdbquery();
list list = new arraylist()
while (rs.next()) {
list.add(rs.getstring(1));
}
return list.iterator();
}

这其实和直接返回list没区别,还是浪费内存。

就此篇文章引起争论:

1.关闭数据库连接rs是否还能使用?

http://dev.csdn.net/develop/article/17/17705.shtm

如下:

在connection上调用close方法会关闭statement和resultset吗?

级联的关闭这听起来好像很有道理,而且在很多地方这样做也是正确的,通常这样写
connection con = getconnection();//getconnection is your method
preparedstatement ps = con.preparestatement(sql);
resultset rs = ps.executequery();
……
///rs.close();
///ps.close();
con.close();  // no!
这样做的问题在于connection是个接口,它的close实现可能是多种多样的。在普通情况下,你用drivermanager.getconnection()得到一个connection实例,调用它的close方法会关闭statement和resultset。但是在很多时候,你需要使用数据库连接池,在连接池中的得到的connection上调用close方法的时候,connection可能并没有被释放,而是回到了连接池中。它以后可能被其它代码取出来用。如果没有释放statement和resultset,那么在connection上没有关闭的statement和resultset可能会越来越多,那么……
相反,我看到过这样的说法,有人把connection关闭了,却继续使用resultset,认为这样是可以的,引发了激烈的讨论,到底是怎么回事就不用我多说了吧。(作者意思是:rs的资源没有释放,还用的是连接池中的conn)

所以我们必须很小心的释放数据库资源,下面的代码片断展示了这个过程

connection con = null;
preparedstatement ps = null;
resultset rs = null;

try {
    con = getconnection();//getconnection is your method
    ps = con.preparestatement(sql);
    rs = ps.executequery();
    ///...........
}
catch (sqlexception ex) {
    ///错误处理
}
finally{
    try {
        if(ps!=null)
            ps.close();
    }
    catch (sqlexception ex) {
        ///错误处理
    }
    try{
        if(con!=null)
            con.close();
    }
    catch (sqlexception ex) {
        ///错误处理
    }
}

很麻烦是不是?但为了写出健壮的程序,这些处理是必须的。

大意如下:

如果不使用连接池机制, 关闭connection, 必然关闭resultset!
如果使用连接池, 所谓的关闭connection, 其实是将连接返回给了连接池,
连接对象依然存在, 所以这实际上不叫关闭!

2.性能问题

如果不是为了模式,用resultset遍历是最快的,比放进collection在遍历要快很多,装进collection不也是resultset的遍历吗。在jsp中遍历resultset占用数据库资源的说法是不对的。jsp的后台实现就是servlet。为了模式性能上是要付出代价的。

要是你在collection里面依然采用直接包装resultset的方式,在性能上没有丝毫好处。唯一的好处是对jsp程序员屏蔽了rs的访问。
collection需要对java.sql.resultset的数据进行page的包装。才有性能上的效果。

扫描关注微信公众号