1. 程式人生 > >Mybatis實現物理分頁

Mybatis實現物理分頁

Mybatis的自帶分頁方法只是邏輯分頁,如果資料量很大,記憶體會溢位,不知道為什麼開源組織不在裡面實現類似Hibernate的物理分頁處理方法。在不改動Mybatis原始碼的情況下,怎麼使Mybatis支援物理分頁呢?下面我們來看看。

(1)新建一個Java類Dialect.java,該類的內容如下:

Java程式碼  
  1. package org.mybatis.extend.interceptor;  

  2. publicabstractclass Dialect {  

  3. publicstaticenum Type{  

  4.         MYSQL,  

  5.         ORACLE  

  6.     }  

  7. publicabstract String getLimitString(String sqlint skipResults,  int maxResults);  

  8. }  

(2)新建一個Java類OracleDialect.java,該類繼承Dialect 類,具體的內容如下:

Java程式碼  
  1. package org.mybatis.extend.interceptor;  

  2. publicclass OracleDialect  extends Dialect{  

  3. /* (non-Javadoc)

  4.      * @see org.mybatis.extend.interceptor.IDialect#getLimitString(java.lang.String, int, int)

  5.      */

  6.     @Override

  7. public String getLimitString(String sqlint offset,  int limit) {  

  8.         sql = sql.trim();  

  9.         StringBuffer pagingSelect = new StringBuffer(sql.length() +  100 );  

  10.         pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");  

  11.         pagingSelect.append(sql);  

  12.         pagingSelect.append(" ) row_ ) where rownum_ > ").append(offset).append( " and rownum_ <= ").append(offset + limit);  

  13. return pagingSelect.toString();  

  14.     }  

  15. }  

(3)新建一個Mybaits的攔截器PaginationInterceptor.java,實現Interceptor介面,該類的內容如下:

Java程式碼 

package org.mybatis.extend.interceptor

import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.ibatis.executor.parameter.DefaultParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import platform.pages.mybatis.dialects.MysqlDialect;
import platform.pages.mybatis.dialects.OracleDialect;

/**
 * Mybaits的攔截器
 *
 * @author fhx 2013-1-27 下午03:04:33
 */
@Intercepts( { @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class PaginationInterceptor implements Interceptor {

 protected static Logger log = LoggerFactory.getLogger(PaginationInterceptor.class);

 @Override
 public Object intercept(Invocation invocation) throws Throwable {
  StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
  BoundSql boundSql2 = statementHandler.getBoundSql();
  List list = boundSql2.getParameterMappings();
  MetaObject metaStatementHandler = MetaObject.forObject(statementHandler);
  RowBounds rowBounds = (RowBounds) boundSql2.getParameterObject();
  if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
   return invocation.proceed();
  }
  String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
  Configuration configuration = (Configuration) metaStatementHandler.getValue("delegate.configuration");
  Dialect.Type databaseType = null;
  try {
   databaseType = Dialect.Type.valueOf(configuration.getVariables().getProperty("dialect").toUpperCase());
  } catch (Exception e) {
   System.out.println("mybatis-config.xml中未設定資料庫型別");
  }
  if (databaseType == null) {
   throw new RuntimeException(
     "the value of the dialect property in configuration.xml is not defined : " + configuration.getVariables().getProperty("dialect"));
  }
  Dialect dialect = null;
  switch (databaseType) {
  case ORACLE: // oracle 分頁
   dialect = new OracleDialect();
   break;
  case MYSQL: // MySQL分頁
   dialect = new MysqlDialect();
   break;
  }
  metaStatementHandler.setValue("delegate.boundSql.sql", dialect.getLimitString(originalSql, rowBounds.getOffset(), rowBounds.getLimit()));

  metaStatementHandler.setValue("delegate.rowBounds.offset",RowBounds.NO_ROW_OFFSET);

  metaStatementHandler.setValue("delegate.rowBounds.limit",RowBounds.NO_ROW_LIMIT);

  if (log.isDebugEnabled()) {
   BoundSql boundSql = statementHandler.getBoundSql();
   log.debug(" 生成分頁SQL : " + boundSql.getSql());
  }
  return invocation.proceed();
 }

 @Override
 public Object plugin(Object target) {
  return Plugin.wrap(target, this);
 }

 @Override
 public void setProperties(Properties arg0) {

 }

}

 (4)將Mybatis的攔截器配置到Mybatis的全域性配置檔案(mybatis.cfg.xml)中,具體如下:

Java程式碼 
  1. <?xml version="1.0" encoding= "UTF-8" ?>  

  2. <!DOCTYPE configuration PUBLIC   

  3. "-//mybatis.org//DTD Config 3.0//EN"

  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">  

  5. <configuration>  

  6.     <properties>  

  7.               <property name="dialect" value= />  

  8.     </properties>  

  9.     <plugins>  

  10.             <plugin interceptor="org.mybatis.extend.interceptor.PaginationInterceptor"/>  

  11.     </plugins>  

  12. </configuration>  

(5)使用方法同Mybatis邏輯分頁一樣,攔截器會自動攔截執行SQL的地方,加上分頁程式碼:

Java程式碼 
  1. getSqlSession().selectList(sqlId, paramMap,new RowBounds(pageId, pageSize)); 

              (6) 和spring整合封裝有superDao

public class SupperDao extends SqlSessionDaoSupport{
 
 protected Logger log = LoggerFactory.getLogger(getClass());
 
 /**
  * 儲存
  * @param key
  * @param object
  */
 public void save(String key, Object object) {
  getSqlSession().insert(key, object);
 }
 
 /**
  * 刪除
  * @param key
  * @param id
  */
 public void delete(String key, Serializable id) {
  getSqlSession().delete(key, id);
 }
 
 /**
  * 刪除
  * @param key
  * @param object
  */
 public void delete(String key, Object object) {
  getSqlSession().delete(key, object);
 }
 
 /**
  * 查詢 返回一個結果
  * @param <T>
  * @param key
  * @param params
  * @return
  */
 public <T> T get(String key, Object params) {
  return (T) getSqlSession().selectOne(key, params);
 }
 
 /**
  * 查詢 返回多個結果
  * @param <T>
  * @param key
  * @return
  */
 public <T> List<T> findList(String key) {
  return getSqlSession().selectList(key);
 }
 
 /**
  * 分頁查詢
  * @param <T>
  * @param key
  * @param offset
  * @param pageSize
  * @return
  */
 public <T> List<T> findList(String key,int offset,int pageSize) {
  return getSqlSession().selectList(key,new RowBounds(offset, pageSize));
 }
 
 /**
  * 查詢 可帶引數 返回多個結果
  * @param <T>
  * @param key
  * @param params
  * @return
  */
 public <T> List<T> findList(String key, Object params) {
  return getSqlSession().selectList(key, params);
 }
 
 /**
  * 分頁查詢 可帶引數
  * @param <T>
  * @param key
  * @param params
  * @param pageNo
  * @param pageSize
  * @return
  */
 public <T> List<T> findList(String key, Object params,int pageOffset,int pageSize) {
  return getSqlSession().selectList(key, params,new RowBounds(pageOffset, pageSize));
 }