2013-07-03 32 views
2

我正在使用c3p0。我建立了如下集合,c3p0 Prepared Statement沒有明顯原因關閉

cpds = new ComboPooledDataSource(); 
cpds.setJdbcUrl(...); 
/* connection setup */ 
spds.setMaxStatements(200); 

我有一個對象可以在初始化時準備幾個準備好的語句。爲此,我從PooledDataSource中獲取一個連接(con = getConnection()),然後準備一個語句(例如,PreparedStatement stmt = con.preparedStatemet(/*sql*/))。準備好的語句作爲私有變量存儲在對象中,當前連接在初始化結束時關閉(con.close())。準備好的語句用於對象的方法。

對於更新數據庫的預處理語句,這很好。然而,當我調用使用準備好的語句(stmt.executeQuery())查詢數據庫的方法,我得到了以下的SQLException

java.sql.SQLException: You can't operate on a closed Statement!!! 
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118) 
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77) 
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:127) 

難道我得到關於C3P0的使用出問題了嗎?

非常感謝提前!

編輯:顯然,我的問題部分基於我的理解不足。正如在明確的答案中指出的那樣,PreparedStatement屬於一個連接,並且每當連接關閉時,關聯的語句也應該關閉。但是,如果是這樣的話,我不明白c3p0的語句緩存的用途是什麼。

+0

我猜測連接會關閉它所瞭解的語句。然而,我很努力地在某處找到一個明確的參考,這與此一致。 –

回答

7

你應該得到相同的異常調用executeUpdate()。 JDBC連接和語句池的設計是透明的:對於非池化數據源,同樣的API也應該用於池式版本。性能會有很大差異,但代碼應該在語義上可以互換。

在一個unpooled的環境中,它應該很明顯,爲什麼你的方法失敗了:一個聲明,準備或以其他方式,是一個連接的孩子,沒有它,它不能運作。你希望在彙集的環境中,即使Connection已經「關閉」,它仍然應該存在於池中,所以,這些語句可能是好的。但是這是一個非常糟糕的主意(如果你在嘗試更新後確實成功了,那麼在父連接關閉後),再次,這將是一個錯誤,一個錯誤。)一旦Connection被「關閉」它回到游泳池,但不是永遠。其他客戶將檢查出來,並開始執行不應被陳舊陳述中斷的交易工作。最終連接將會從池中過期。那麼應該如何處理您保留的PreparedStatements呢?

c3p0 pool聲明透明,這意味着你應該使用完全相同的API,你會用到沒有池。每次在Connection上調用prepareStatement(...)。如果您已經在c3p0中啓用了語句池(就像您一樣),那麼內部c3p0將檢查語句是否已經準備好,如果是,它將悄悄地使用緩存版本,而不是將請求轉發給dbms。

我希望這有助於!