`

难经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,多加上输入参数校验,也不会搞出这一档子事啊!

2
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics