高手请看:Hibernate Oracle9Dialect 翻页查询的一个BUG!!!!
我的一个项目使用了Hibernate3操作Oracle9i数据库,遇到一个很奇怪的问题,即在按某些使用了聚合函数的值的升序排序后,翻页到一定页数(通常是3或5)以后,显示的内容不会变化,即出现不是期望的查询结果.
刚开始而般排查,找不原因.后来通过查Hibernate 包中的Oracle9Dialect及OracleDialect的源码,将Dialect换成 OracleDialect后问题解决.
但是,问题虽解决了,根源何在呢?为什么Oracle9却要用到OracleDialect(源码注解中说这是兼容8i)的才能解决问题呢?!
查看源码,发现两都取得分页查询字符串的方式是有点区别的(在 getlimitString()方法中).
在Oracle9Dialect中:
public String getLimitString(String sql, boolean hasOffset) {
sql = sql.trim();
boolean isForUpdate = false;
if ( sql.toLowerCase().endsWith(" for update") ) {
sql = sql.substring( 0, sql.length()-11 );
isForUpdate = true;
}
StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );
if (hasOffset) {
pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
}
else {
pagingSelect.append("select * from ( ");
}
pagingSelect.append(sql);
if (hasOffset) {
pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");
}
else {
pagingSelect.append(" ) where rownum <= ?");
}
if (isForUpdate) pagingSelect.append(" for update");
return pagingSelect.toString();
}
在OracleDialect中:
public String getLimitString(String sql, boolean hasOffset) {
sql = sql.trim();
boolean isForUpdate = false;
if ( sql.toLowerCase().endsWith(" for update") ) {
sql = sql.substring( 0, sql.length()-11 );
isForUpdate = true;
}
StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );
if (hasOffset) {
pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
}
else {
pagingSelect.append("select * from ( ");
}
pagingSelect.append(sql);
if (hasOffset) {
pagingSelect.append(" ) row_ ) where rownum_ <= ? and rownum_ > ?");
}
else {
pagingSelect.append(" ) where rownum <= ?");
}
if (isForUpdate) pagingSelect.append(" for update");
return pagingSelect.toString();
}
两都的区别主要在于,前者:
row_ where rownum <= ?) where rownum_ > ?");
后者:
where rownum_ <= ? and rownum_ > ?
我模拟了我的出问题的查询,使用前者问题重现,使用后者不出问题.
我的语句分别如下:
*************************************************************************
第一种:
select * from (
select rownum row_num ,t.* from(
select Sum(b.disp_Count) , Sum(b.click_Count) ,
Sum(b.total_Price) , Sum(b.return_Cost) ,
avg(b.rank) , b.sta_Date , b.keyword_Name ,
b.union_Name
from Bid_Report b
where (b.sta_Date ='20051129')
group by b.sta_Date, b.keyword_Name, b.union_Name
order by Sum(b.click_Count), b.sta_Date desc
) t where rownum<=60
) where row_num > 40
(在Hibernate3中,Oracle9Dialect的getlimitString()方法采取类似方法)
第二种:
select * from (
select rownum row_num ,t.* from(
select Sum(b.disp_Count) , Sum(b.click_Count) ,
Sum(b.total_Price) , Sum(b.return_Cost) ,
avg(b.rank) , b.sta_Date , b.keyword_Name ,
b.union_Name
from Bid_Report b
where (b.sta_Date ='20051129')
group by b.sta_Date, b.keyword_Name, b.union_Name
order by Sum(b.click_Count), b.sta_Date desc
) t
) where row_num <=60 and row_num>40
(在Hibernate3中,OracleDialect的getlimitString()方法采取类似方法)
**********************************************************************
现在,问题是:为什么采取后都就可以解决问题了呢?这是不是Oracle9Dialect的一个bug呢?!
哪位高手能给我详析,感激不尽!!!!
刚开始而般排查,找不原因.后来通过查Hibernate 包中的Oracle9Dialect及OracleDialect的源码,将Dialect换成 OracleDialect后问题解决.
但是,问题虽解决了,根源何在呢?为什么Oracle9却要用到OracleDialect(源码注解中说这是兼容8i)的才能解决问题呢?!
查看源码,发现两都取得分页查询字符串的方式是有点区别的(在 getlimitString()方法中).
在Oracle9Dialect中:
public String getLimitString(String sql, boolean hasOffset) {
sql = sql.trim();
boolean isForUpdate = false;
if ( sql.toLowerCase().endsWith(" for update") ) {
sql = sql.substring( 0, sql.length()-11 );
isForUpdate = true;
}
StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );
if (hasOffset) {
pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
}
else {
pagingSelect.append("select * from ( ");
}
pagingSelect.append(sql);
if (hasOffset) {
pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");
}
else {
pagingSelect.append(" ) where rownum <= ?");
}
if (isForUpdate) pagingSelect.append(" for update");
return pagingSelect.toString();
}
在OracleDialect中:
public String getLimitString(String sql, boolean hasOffset) {
sql = sql.trim();
boolean isForUpdate = false;
if ( sql.toLowerCase().endsWith(" for update") ) {
sql = sql.substring( 0, sql.length()-11 );
isForUpdate = true;
}
StringBuffer pagingSelect = new StringBuffer( sql.length()+100 );
if (hasOffset) {
pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
}
else {
pagingSelect.append("select * from ( ");
}
pagingSelect.append(sql);
if (hasOffset) {
pagingSelect.append(" ) row_ ) where rownum_ <= ? and rownum_ > ?");
}
else {
pagingSelect.append(" ) where rownum <= ?");
}
if (isForUpdate) pagingSelect.append(" for update");
return pagingSelect.toString();
}
两都的区别主要在于,前者:
row_ where rownum <= ?) where rownum_ > ?");
后者:
where rownum_ <= ? and rownum_ > ?
我模拟了我的出问题的查询,使用前者问题重现,使用后者不出问题.
我的语句分别如下:
*************************************************************************
第一种:
select * from (
select rownum row_num ,t.* from(
select Sum(b.disp_Count) , Sum(b.click_Count) ,
Sum(b.total_Price) , Sum(b.return_Cost) ,
avg(b.rank) , b.sta_Date , b.keyword_Name ,
b.union_Name
from Bid_Report b
where (b.sta_Date ='20051129')
group by b.sta_Date, b.keyword_Name, b.union_Name
order by Sum(b.click_Count), b.sta_Date desc
) t where rownum<=60
) where row_num > 40
(在Hibernate3中,Oracle9Dialect的getlimitString()方法采取类似方法)
第二种:
select * from (
select rownum row_num ,t.* from(
select Sum(b.disp_Count) , Sum(b.click_Count) ,
Sum(b.total_Price) , Sum(b.return_Cost) ,
avg(b.rank) , b.sta_Date , b.keyword_Name ,
b.union_Name
from Bid_Report b
where (b.sta_Date ='20051129')
group by b.sta_Date, b.keyword_Name, b.union_Name
order by Sum(b.click_Count), b.sta_Date desc
) t
) where row_num <=60 and row_num>40
(在Hibernate3中,OracleDialect的getlimitString()方法采取类似方法)
**********************************************************************
现在,问题是:为什么采取后都就可以解决问题了呢?这是不是Oracle9Dialect的一个bug呢?!
哪位高手能给我详析,感激不尽!!!!
...全文
相关推荐
hibernate中所有数据库方言
hibernate支持的所有数据库方言。用起来很方便。
hibernate的分页查询
Hibernate底层如何实现分页的呢?实际上Hibernate的查询定义在net.sf.hibernate.loader.Loader这个类里面,仔细阅读该类代码,就可以把问题彻底搞清楚
简单了解mysql方言dialect
主要介绍了简单了解数据库方言dialect,数据库方言也是如此,MySQL 是一种方言,Oracle 也是一种方言,MSSQL 也是一种方言,他们之间在遵循 SQL 规范的前提下,都有各自的扩展特性,需要的朋友可以参考下
Hibernate分页查询原理解读
Hibernate分页查询原理解读 , 忘记以前在哪看的了, 现在贴出来和大家分享一下。
Hibernate分页
系统中都是非常头疼的事情,有的数据库在语法上支持分页,而有的数据库则需要使用可滚动游标来实现,并且在不支持可滚动游标的系统上只能使用单向游标逐步接近要取得的数据。 Hibernate提供了一个支持跨系统的分页机制,这样无论底层是什么样的数据库都能用统一的接口进行分页操作。


