Mybatis實現物理分頁
Mybatis的自帶分頁方法只是邏輯分頁,如果資料量很大,記憶體會溢位,不知道為什麼開源組織不在裡面實現類似Hibernate的物理分頁處理方法。在不改動Mybatis原始碼的情況下,怎麼使Mybatis支援物理分頁呢?下面我們來看看。
(1)新建一個Java類Dialect.java,該類的內容如下:
Java程式碼-
package org.mybatis.extend.interceptor;
-
publicabstractclass Dialect {
-
publicstaticenum Type{
-
MYSQL,
-
ORACLE
-
}
-
publicabstract String getLimitString(String sql, int skipResults, int maxResults);
-
}
(2)新建一個Java類OracleDialect.java,該類繼承Dialect 類,具體的內容如下:
Java程式碼-
package org.mybatis.extend.interceptor;
-
publicclass OracleDialect extends Dialect{
-
/* (non-Javadoc)
-
* @see org.mybatis.extend.interceptor.IDialect#getLimitString(java.lang.String, int, int)
-
*/
-
@Override
-
public String getLimitString(String sql, int offset, int limit) {
-
sql = sql.trim();
-
StringBuffer pagingSelect = new StringBuffer(sql.length() + 100 );
-
pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
-
pagingSelect.append(sql);
-
pagingSelect.append(" ) row_ ) where rownum_ > ").append(offset).append( " and rownum_ <= ").append(offset + limit);
-
return pagingSelect.toString();
-
}
-
}
(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程式碼-
<?xml version="1.0" encoding= "UTF-8" ?>
-
<!DOCTYPE configuration PUBLIC
-
"-//mybatis.org//DTD Config 3.0//EN"
-
"http://mybatis.org/dtd/mybatis-3-config.dtd">
-
<configuration>
-
<properties>
-
<property name="dialect" value= />
-
</properties>
-
<plugins>
-
<plugin interceptor="org.mybatis.extend.interceptor.PaginationInterceptor"/>
-
</plugins>
-
</configuration>
(5)使用方法同Mybatis邏輯分頁一樣,攔截器會自動攔截執行SQL的地方,加上分頁程式碼:
Java程式碼-
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));
}