淺析Hibernate分頁管理
本文向大家介紹Hibernate分頁,可能好多人還不了解Hibernate分頁,沒有關(guān)系,看完本文你肯定有不少收獲,希望本文能教會你更多東西。
Hibernate中,通過對不同數(shù)據(jù)庫的統(tǒng)一接口設(shè)計(jì),實(shí)現(xiàn)了透明化、通用化的分頁實(shí)現(xiàn)機(jī)制。
通過Criteria.setFirstResult和Criteria.setFetchSize方法設(shè)定分頁范圍,如:
- Criteria criteria = session.createCriteria(TUser.class);
 - criteria.add(Expression.eq("age", "20"));
 - //從檢索結(jié)果中獲取第100條記錄開始的20條記錄
 - criteria.setFirstResult(100);
 - criteria.setFetchSize(20);
 
通過Query.setFirstResult和Query.setMaxResults方法也可以設(shè)定分頁范圍,如:
- Query query = session.createQuery("from TUser");
 - query.setFirstResult(100);
 - query.setMaxResults(20); // query.setFetchSize(20);
 - List list = query.list();
 
Hibernate中,抽象類org.hibernate.dialect.Dialect指定了所有底層數(shù)據(jù)庫的對外統(tǒng)一接口,通過針對不同數(shù)據(jù)庫提供相應(yīng)的Dialect實(shí)現(xiàn),數(shù)據(jù)庫之間的差異性得以消除,從而為上層機(jī)制提供了透明的、數(shù)據(jù)庫無關(guān)的存儲層基礎(chǔ)。對于分頁機(jī)制而言,Dialect中定義了一個方法如下:
- /**
 - * Add a LIMIT clause to the given SQL SELECT
 - *
 - * @return the modified SQL
 - */
 - public String getLimitString(String querySelect, boolean hasOffset) {
 - throw new UnsupportedOperationException( "paged queries not supported" );
 - }
 - public String getLimitString(String querySelect, int offset, int limit) {
 - return getLimitString( querySelect, offset>0 );
 - }
 
此方法用于在現(xiàn)有Select語句基礎(chǔ)上,根據(jù)各個數(shù)據(jù)庫自身特性,構(gòu)造對應(yīng)的記錄返回限定子句。如MySQL中對應(yīng)的記錄限定子句為Limit,Oracle中,通過rownum子句實(shí)現(xiàn)。MySQLDialect中的getLimitString實(shí)現(xiàn):
- public String getLimitString(String sql, boolean hasOffset) {
 - return new StringBuffer( sql.length()+20 )
 - .append(sql)
 - .append( hasOffset ? " limit ?, ?" : " limit ?")
 - .toString();
 - }
 
MySQLDialect.getLimitString方法的實(shí)現(xiàn)實(shí)際上是在給定的Select語句后追加MySQL所提供的專有SQL子句limit來實(shí)現(xiàn)。
Oracle9Dialect中的getLimitString實(shí)現(xiàn):
- public String getLimitString(String sql, boolean hasOffset) {
 - sqlsql = sql.trim();
 - boolean isForUpdate = false;
 - if ( sql.toLowerCase().endsWith(" for update") ) {
 - sqlsql = 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();
 - }
 
通過Oracle特有的rownum子句來實(shí)現(xiàn)數(shù)據(jù)部分的讀取。SQLServerDialect中的getLimitString實(shí)現(xiàn):
- public String getLimitString(String querySelect, int offset, int limit) {
 - if ( offset > 0 ) {
 - throw new UnsupportedOperationException( "sql server has no offset" );
 - }
 - return new StringBuffer( querySelect.length()+8 )
 - .append(querySelect)
 - .insert( getAfterSelectInsertPoint(querySelect), " top " + limit )
 - .toString();
 - }
 
通過SQLServer特有的top子句實(shí)現(xiàn)。HSQLDialect中的getLimitString實(shí)現(xiàn):
- public String getLimitString(String sql, boolean hasOffset) {
 - return new StringBuffer( sql.length() + 10 )
 - .append( sql )
 - .insert( sql.toLowerCase().indexOf( "select" ) + 6, hasOffset ? " limit ? ?" : " top ?" )
 - .toString();
 - }
 
大多數(shù)主流數(shù)據(jù)庫都提供了數(shù)據(jù)部分讀取機(jī)制,而對于某些沒有提供相應(yīng)機(jī)制的數(shù)據(jù)庫而言,Hibernate也通過其他途徑實(shí)現(xiàn)了分頁,如通過Scrollable ResultSet,如果JDBC不支持Scrollable ResultSet,Hibernate也會通過ResultSet的next方法進(jìn)行記錄定位。Hibernate通過底層對分頁機(jī)制的良好封裝,使得開發(fā)人員無需關(guān)心數(shù)據(jù)分頁的細(xì)節(jié)實(shí)現(xiàn),將數(shù)據(jù)邏輯和存儲邏輯分離開來,在提高生產(chǎn)效率的同時,也大大加強(qiáng)了系統(tǒng)在不同數(shù)據(jù)庫平臺之間的可移植性。
【編輯推薦】
- 如何解決Struts Hibernate的整合問題
 - 對Hibernate中g(shù)et()與load()不同點(diǎn)分析
 - Struts-Spring-Hibernate案例
 - 簡述Hibernate配置連接池
 - 對Hibernate中g(shù)et()與load()不同點(diǎn)分析
 















 
 
 
 
 
 
 