[Java][MyBatis]物理分頁實現__資料庫專區

來源:互聯網
上載者:User

 [Java][MyBatis]物理分頁實現

Mybatis3.0出來已有段時間了,其實自己挺喜歡這樣的一個持久化架構的,因為它簡單實用,學習成本低。Mybatis3.0在整體結構上和ibatis2.X差不多,改進特性如下:

1.        解析xml引進了Xpath,不像ibatis2.x那樣業餘

2.        動態sql用OGNL解析

3.        加入註解配置sql,感覺沒什麼特別大的用途,我更喜歡xml方式,代碼和配置分離,這也是ibatis的初衷

4.        加強了緩衝這塊的功能。Mybatis3.0把緩衝模組分得更細,分為“持久實現(prepetual)”和“資源回收策略實現(eviction)”,更好的對緩衝功能進行自己組合和擴充

5.        終於加入的plugin功能,就像struts一樣,這樣就可以很好的擴充內部的Executor,,StatementHandler….等內部對象功能。

 

 

MyBatis的分頁功能還是基於記憶體分頁(尋找出所有記錄再取出位移量的記錄,如果jdbc驅支援absolute定位或者rs.next()到指定位移位置),其實這樣的分頁實現基本沒用,特別是大量資料情況下。不過我們可以通過plugin功能來擴充MyBatis的分頁功能、實現物理分頁。具體做法如下:

1、編寫分頁外掛程式類:

/** * 著作權:華信軟體 * 項目名稱:ACWS架構類 * 建立者: Wangdf * 建立日期: 2014-4-2 * 檔案說明: ACWS架構分頁介面類 */package framework.core.interceptor;import java.sql.Connection;import java.util.Map;import java.util.Properties;import org.apache.commons.collections.MapUtils;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.reflection.factory.DefaultObjectFactory;import org.apache.ibatis.reflection.factory.ObjectFactory;import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;import org.apache.ibatis.session.Configuration;import org.apache.ibatis.session.RowBounds;import framework.core.util.DBUtil;/** * ACWS架構分頁介面類 * @author Wangdf * */@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })public class PaginationInterceptor implements Interceptor {    private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();MetaObject metaStatementHandler =  MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,                DEFAULT_OBJECT_WRAPPER_FACTORY);RowBounds rowBounds = (RowBounds) metaStatementHandler.getValue("delegate.rowBounds");if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {return invocation.proceed();}        // 分離代理對象鏈(由於目標類可能被多個攔截器攔截,從而形成多次代理,通過下面的兩次迴圈可以分離出最原始的的目標類)        while (metaStatementHandler.hasGetter("h")) {            Object object = metaStatementHandler.getValue("h");            metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);        }        // 分離最後一個代理對象的目標類        while (metaStatementHandler.hasGetter("target")) {            Object object = metaStatementHandler.getValue("target");            metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);        }        BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");            String sql = boundSql.getSql();StringBuffer sbSql = new StringBuffer();    // 重寫sqlConfiguration configuration = (Configuration)metaStatementHandler.getValue("delegate.configuration");DBUtil dbUtil = new DBUtil(configuration);        if(dbUtil.isMySQL()){        sbSql.append(sql).append(" LIMIT ").append(rowBounds.getOffset()).append(", ").append(rowBounds.getLimit());            metaStatementHandler.setValue("delegate.boundSql.sql", sbSql.toString());                        // 採用物理分頁後,就不需要mybatis的記憶體分頁了,所以重設下面的兩個參數            metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);            metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);} else if(dbUtil.isOracle()){sbSql.append("SELECT * ");sbSql.append("  FROM (SELECT ROWNUM RN, NOPAGESQL.*   ");sbSql.append("          FROM (").append(sql).append(") NOPAGESQL ");sbSql.append("         WHERE ROWNUM <= ").append(rowBounds.getLimit()+rowBounds.getOffset()).append(")");sbSql.append(" WHERE RN >= ").append(rowBounds.getOffset());        metaStatementHandler.setValue("delegate.boundSql.sql", sbSql.toString());                // 採用物理分頁後,就不需要mybatis的記憶體分頁了,所以重設下面的兩個參數        metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);        metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);} else {}                // 將執行權交給下一個攔截器        return invocation.proceed();}@Overridepublic Object plugin(Object target) {        // 當目標類是StatementHandler類型時,才封裝目標類,否者直接返回目標本身,減少目標被代理的次數        if (target instanceof StatementHandler) {            return Plugin.wrap(target, this);        } else {            return target;        }}@Overridepublic void setProperties(Properties properties) {// TODO Auto-generated method stub}}

 

2、配置讀取類

/** * 著作權:華信軟體 * 項目名稱:ACWS架構類 * 建立者: Wangdf * 建立日期: 2014-4-2 * 檔案說明: ACWS架構資料庫相關工具類 */package framework.core.util;import org.apache.commons.lang.StringUtils;import org.apache.ibatis.session.Configuration;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * ACWS架構資料庫相關工具類 * @author Wangdf */public class DBUtil {private static final String DBTYPE_MYSQL = "MySQL";//支援的類型:MySQL,Oracleprivate static final String DBTYPE_ORACLE = "Oracle";//支援的類型:MySQL,Oracleprivate static Logger logger = LoggerFactory.getLogger(DBUtil.class);private Configuration configuration = null;private String dbType = "";private String defaultDateFormat = "";public DBUtil(Configuration configuration){if(configuration == null){logger.error("系統啟動失敗:MyBatis Configuration 對象為空白。");throw new IllegalArgumentException("系統啟動失敗:MyBatis Configuration 對象為空白。");}this.configuration = configuration;this.dbType = this.configuration.getVariables().getProperty("dbtype");    if(StringUtils.isBlank(dbType)){    logger.error("資料庫類型沒有配置。");    } else {    logger.info("資料庫類型為:"+dbType);    }this.defaultDateFormat = this.configuration.getVariables().getProperty("defaultDateFormat");    if(StringUtils.isBlank(this.defaultDateFormat)){    this.defaultDateFormat="yyyy-MM-dd";    logger.info("資料庫日期預設格式字串沒有指定。系統預設為:yyyy-MM-dd");    } else {    logger.info("資料庫日期預設格式字串:"+this.defaultDateFormat);    }}/** * 判斷是否是Oracle資料庫 * @return * @author wangdf */public boolean isOracle(){return DBTYPE_ORACLE.equals(this.dbType);}/** * 判斷是否是MySQL資料庫 * @return * @author wangdf */public boolean isMySQL(){return DBTYPE_MYSQL.equals(this.dbType);}/** * 取得資料庫類型 * @return * @author wangdf */public String getDbType(){return this.dbType;}/** * 取得預設日期格式 * @return * @author wangdf */public String getDefaultDateFormat(){return this.defaultDateFormat;}}


 

3、在mybatis全域設定檔設定

<?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="dbtype" value="MySQL"/><!-- 資料庫類型:MySQL、Oracle -->    <property name="defaultDateFormat" value="yyyy-MM-dd"/></properties><settings><setting name="cacheEnabled" value="true" /><setting name="lazyLoadingEnabled" value="true" /><setting name="multipleResultSetsEnabled" value="true" /><setting name="useColumnLabel" value="true" /><setting name="defaultExecutorType" value="REUSE" /><setting name="defaultStatementTimeout" value="25000" /></settings><plugins><plugin interceptor="framework.core.interceptor.PaginationInterceptor"></plugin></plugins></configuration>


 


 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.