查詢資料庫後返回Iterator

來源:互聯網
上載者:User

既然我們把資料庫訪問封裝起來了,那麼如果查詢資料庫返回的是一系列結果,比如我們從資料庫中得到所有人的使用者名稱,然後在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的封裝。才有效能上的效果。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.