難經1:Sybase和Hibernate不對付?

[問題] 一直在使用Hibernate提供的通用分頁機制,在通過查詢api設置分頁後,執行查詢一直正常。突一日,使用包裝了這部分的分頁組件的W君,報告分頁查詢時,拋出奇怪異常,數據庫是Sybase:

09:26:24,265 [main] ERROR JDBCExceptionReporter : JZ0BT: 類型 TYPE_FORWARD_ONLY 的 ResultSets 不支持 absolute(int) 方法。
org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on Hibernate data access; nested exception is org.hibernate.exception.GenericJDBCException: could not execute query
Caused by: org.hibernate.exception.GenericJDBCException: could not execute query
	at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
	at org.hibernate.loader.Loader.doList(Loader.java:2214)
	at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2095)
	at org.hibernate.loader.Loader.list(Loader.java:2090)
	at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:289)
	at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1695)
	at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:142)
	at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:150)
Caused by: java.sql.SQLException: JZ0BT: 類型 TYPE_FORWARD_ONLY 的 ResultSets 不支持 absolute(int) 方法。
 at com.sybase.jdbc3.jdbc.ErrorMessage.raiseError(ErrorMessage.java:515)
 at com.sybase.jdbc3.jdbc.SybResultSet.checkForScrollability(SybResultSet.java:1757)
 at com.sybase.jdbc3.jdbc.SybResultSet.absolute(SybResultSet.java:717)
 at org.apache.commons.dbcp.DelegatingResultSet.absolute(DelegatingResultSet.java:334)
 at org.hibernate.loader.Loader.advance(Loader.java:1469)
 at org.hibernate.loader.Loader.getResultSet(Loader.java:1783)
 at org.hibernate.loader.Loader.doQuery(Loader.java:662)
 at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
 at org.hibernate.loader.Loader.doList(Loader.java:2211)

 [探幽]

從異常看,第一反應,好像是查詢時未設置遊標類型,導致不支持調用absolute調用。這不是一個老生長談的問題麼,難道Hibernate在建立連接時,未設置相應屬性?但不可能啊,Hibernate的分頁查詢要有這麼大的BUG,也不用等我來發現了。在查看Hibernate的代碼後,也看到它明確設置了遊標類型;

第二反應,Sybase驅動或Sybase版本問題?之前在jconn2、jconn3驅動上做過單元測試,沒有問題,爲了確認,再跑了幾次,沒有問題。還有,報出問題的Sybase版本與測試的Sybase版本基本一致,只有小版本差異,應該不會有多大問題。所以,也不太可能;

第三反應,算了先不想了,Google吧,也許人家是早就搞定過的問題了。於是填入多個搜索詞+Sybase的錯誤碼->GO,奇怪,確實有兩個提問這個的,csdn上一個,hibernate論壇上一個,一看都是05年的了,而且代碼設置分頁的代碼和我一模一樣,看看回答,結果不多,全看下來,大概都是和我第一反應和第二反應相同的思路,而後續竟淹沒無解了......

難道。。。難道Sybase真和Hibernate不對付,偶爾不爽了就發個飈,擺上一道?否則怎麼沒碰到其他數據庫報這個問題?

 

[解難]

歇了一晚,回頭再想想,覺得不甘心,又總覺得哪有不妥,記得原來在調用Hibernate的api,設置firstResult時,是直接通過頁數,算出第一行記錄的:

query.setFirstResult((pq.getPageIndex()-1) * pq.getPageRows());

 

這和Hibernate論壇上提問的那位代碼一致,當初在通過頁碼計算首記錄位置時,曾閃過:如果計算得到負數,Hibernate會報錯麼。基於MySQL的測試表明,Hibernate好像是把負數忽略了,變成從0開始,後來在Sybase上的測試,分頁數都是正確的,沒有再試過負頁數。現在據說報錯也是偶然發生,那是不是有可能:在偶然輸入錯誤的分頁數時,負分頁數直接傳到了後臺給hibernate,然後sybase在接受這個負參數時報出異常;而其他時候又運行正常。

想到這,我眼睛一亮:),立即掏出Eclipse,祭出JUnit,在原來的測試上加上負頁數的輸入斷言,然後選擇在Sybase上運行...... 整個世界清靜了,W君報告的偶發錯誤終於重現——JZ0BT。由亮而暗,我的眼裏透出了一絲苦澀,唉,又是一個低級錯誤啊,當初要不是太相信Hibernate,多加上輸入參數校驗,也不會搞出這一檔子事啊!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章