国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

詳解Mybatis極其(最)簡(好)單(用)的一個分頁插件

2019-11-26 13:22:41
字體:
來源:轉載
供稿:網友

注意:這篇博客已經和當前的分頁插件完全不一樣了,所以建議大家通過上面項目地址查看最新的源碼和文檔來了解。

以前為Mybatis分頁查詢發愁過,而且在網上搜過很多相關的文章,最后一個都沒采用。在分頁的地方完全都是手寫分頁SQL和count的sql,總之很麻煩。

后來有一段時間想從Mybatis內部寫一個分頁的實現,我對LanguageDriver寫過一個實現,自動分頁是沒問題了,但是查詢總數(count)仍然沒法一次性解決,最后不了了之。

最近又要用到分頁,為了方便必須地寫個通用的分頁類,因此又再次參考網上大多數的Mybatis分頁代碼。

實際上在很早之前,有人在github上開源過一個實現,支持MySQL,Oracle,sqlserver的,和上面這個參考的比較類似,考慮的更全面。但是我覺得太多類太麻煩了,所以自己實現了一個只有一個攔截器的類,實際上可以分為兩個類,其中一個類被我寫成靜態類放在了攔截器中,你也可以將Page類提取出來,方便使用Page。

先說實現方法,該插件只有一個類:PageHelper.Java

攔截器簽名為:

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}), @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})}) 

這里的簽名對整個實現和思想至關重要,首先我攔截prepare方法來改分頁SQL,來做count查詢。然后我攔截handleResultSets方法來獲取最后的處理結果,將結果放到Page對象中。

下面是修改分頁的代碼,是針對Oracle數據進行的修改,如果有用其他數據庫的,自己修改這里的代碼就可以。

/**    * 修改原SQL為分頁SQL    * @param sql    * @param page    * @return    */   private String buildPageSql(String sql, Page page) {     StringBuilder pageSql = new StringBuilder(200);     pageSql.append("select * from ( select temp.*, rownum row_id from ( ");     pageSql.append(sql);     pageSql.append(" ) temp where rownum <= ").append(page.getEndRow());     pageSql.append(") where row_id > ").append(page.getStartRow());     return pageSql.toString();   } 

之后在下面的setPageParameter方法中一個selelct count語句,這里也需要根據數據庫類型進行修改:

// 記錄總記錄數 String countSql = "select count(0) from (" + sql + ")"; 

為什么我不提供對各種數據庫的支持呢,我覺得沒必要,還有些數據庫不支持分頁,而且這個插件越簡單對使用的開發人員來說越容易理解,越容易修改。修改成自己需要的分頁查詢肯定不是問題。

最后上完整代碼(繼續看下去,下面還有使用方法):(點擊下載

package com.mybatis.util; import org.apache.ibatis.executor.parameter.ParameterHandler; import org.apache.ibatis.executor.resultset.ResultSetHandler; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.SystemMetaObject; import org.apache.ibatis.scripting.defaults.DefaultParameterHandler; import org.apache.log4j.Logger;  import java.sql.*; import java.util.List; import java.util.Properties;  /**  * Mybatis - 通用分頁攔截器  * @author liuzh/abel533/isea  * Created by liuzh on 14-4-15.  */ @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}),     @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})}) public class PageHelper implements Interceptor {   private static final Logger logger = Logger.getLogger(PageHelper.class);    public static final ThreadLocal<Page> localPage = new ThreadLocal<Page>();    /**    * 開始分頁    * @param pageNum    * @param pageSize    */   public static void startPage(int pageNum, int pageSize) {     localPage.set(new Page(pageNum, pageSize));   }    /**    * 結束分頁并返回結果,該方法必須被調用,否則localPage會一直保存下去,直到下一次startPage    * @return    */   public static Page endPage() {     Page page = localPage.get();     localPage.remove();     return page;   }    @Override   public Object intercept(Invocation invocation) throws Throwable {     if (localPage.get() == null) {       return invocation.proceed();     }     if (invocation.getTarget() instanceof StatementHandler) {       StatementHandler statementHandler = (StatementHandler) invocation.getTarget();       MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);       // 分離代理對象鏈(由于目標類可能被多個攔截器攔截,從而形成多次代理,通過下面的兩次循環       // 可以分離出最原始的的目標類)       while (metaStatementHandler.hasGetter("h")) {         Object object = metaStatementHandler.getValue("h");         metaStatementHandler = SystemMetaObject.forObject(object);       }       // 分離最后一個代理對象的目標類       while (metaStatementHandler.hasGetter("target")) {         Object object = metaStatementHandler.getValue("target");         metaStatementHandler = SystemMetaObject.forObject(object);       }       MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");       //分頁信息if (localPage.get() != null) {       Page page = localPage.get();       BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");       // 分頁參數作為參數對象parameterObject的一個屬性       String sql = boundSql.getSql();       // 重寫sql       String pageSql = buildPageSql(sql, page);       //重寫分頁sql       metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);       Connection connection = (Connection) invocation.getArgs()[0];       // 重設分頁參數里的總頁數等       setPageParameter(sql, connection, mappedStatement, boundSql, page);       // 將執行權交給下一個攔截器       return invocation.proceed();     } else if (invocation.getTarget() instanceof ResultSetHandler) {       Object result = invocation.proceed();       Page page = localPage.get();       page.setResult((List) result);       return result;     }     return null;   }    /**    * 只攔截這兩種類型的    * StatementHandler    * ResultSetHandler    * @param target    * @return    */   @Override   public Object plugin(Object target) {     if (target instanceof StatementHandler || target instanceof ResultSetHandler) {       return Plugin.wrap(target, this);     } else {       return target;     }   }    @Override   public void setProperties(Properties properties) {    }    /**    * 修改原SQL為分頁SQL    * @param sql    * @param page    * @return    */   private String buildPageSql(String sql, Page page) {     StringBuilder pageSql = new StringBuilder(200);     pageSql.append("select * from ( select temp.*, rownum row_id from ( ");     pageSql.append(sql);     pageSql.append(" ) temp where rownum <= ").append(page.getEndRow());     pageSql.append(") where row_id > ").append(page.getStartRow());     return pageSql.toString();   }    /**    * 獲取總記錄數    * @param sql    * @param connection    * @param mappedStatement    * @param boundSql    * @param page    */   private void setPageParameter(String sql, Connection connection, MappedStatement mappedStatement,                  BoundSql boundSql, Page page) {     // 記錄總記錄數     String countSql = "select count(0) from (" + sql + ")";     PreparedStatement countStmt = null;     ResultSet rs = null;     try {       countStmt = connection.prepareStatement(countSql);       BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql,           boundSql.getParameterMappings(), boundSql.getParameterObject());       setParameters(countStmt, mappedStatement, countBS, boundSql.getParameterObject());       rs = countStmt.executeQuery();       int totalCount = 0;       if (rs.next()) {         totalCount = rs.getInt(1);       }       page.setTotal(totalCount);       int totalPage = totalCount / page.getPageSize() + ((totalCount % page.getPageSize() == 0) ? 0 : 1);       page.setPages(totalPage);     } catch (SQLException e) {       logger.error("Ignore this exception", e);     } finally {       try {         rs.close();       } catch (SQLException e) {         logger.error("Ignore this exception", e);       }       try {         countStmt.close();       } catch (SQLException e) {         logger.error("Ignore this exception", e);       }     }   }    /**    * 代入參數值    * @param ps    * @param mappedStatement    * @param boundSql    * @param parameterObject    * @throws SQLException    */   private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,                 Object parameterObject) throws SQLException {     ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);     parameterHandler.setParameters(ps);   }    /**    * Description: 分頁    * Author: liuzh    * Update: liuzh(2014-04-16 10:56)    */   public static class Page<E> {     private int pageNum;     private int pageSize;     private int startRow;     private int endRow;     private long total;     private int pages;     private List<E> result;      public Page(int pageNum, int pageSize) {       this.pageNum = pageNum;       this.pageSize = pageSize;       this.startRow = pageNum > 0 ? (pageNum - 1) * pageSize : 0;       this.endRow = pageNum * pageSize;     }      public List<E> getResult() {       return result;     }      public void setResult(List<E> result) {       this.result = result;     }      public int getPages() {       return pages;     }      public void setPages(int pages) {       this.pages = pages;     }      public int getEndRow() {       return endRow;     }      public void setEndRow(int endRow) {       this.endRow = endRow;     }      public int getPageNum() {       return pageNum;     }      public void setPageNum(int pageNum) {       this.pageNum = pageNum;     }      public int getPageSize() {       return pageSize;     }      public void setPageSize(int pageSize) {       this.pageSize = pageSize;     }      public int getStartRow() {       return startRow;     }      public void setStartRow(int startRow) {       this.startRow = startRow;     }      public long getTotal() {       return total;     }      public void setTotal(long total) {       this.total = total;     }      @Override     public String toString() {       return "Page{" +           "pageNum=" + pageNum +           ", pageSize=" + pageSize +           ", startRow=" + startRow +           ", endRow=" + endRow +           ", total=" + total +           ", pages=" + pages +           '}';     }   } } 

使用該攔截器首先需要在Mybatis配置中配置該攔截器:

<plugins>   <plugin interceptor="com.mybatis.util.PageHelper"></plugin> </plugins> 

配置攔截器的時候需要注意plugins的位置,plugins位置順序如下:

properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, plugins?, environments?, databaseIdProvider?, mappers? 

最后是調用該方法的例子代碼(Service層):

@Override public PageHelper.Page<SysLoginLog> findSysLoginLog(String loginIp,                      String username,                      String loginDate,                      String exitDate,                      String logerr,                      int pageNumber,                      int pageSize) throws BusinessException {   PageHelper.startPage(pageNumber,pageSize);   sysLoginLogMapper.findSysLoginLog(loginIp, username, loginDate, exitDate, logerr);   return PageHelper.endPage(); } 

從上面可以看到使用該插件使用起來是很簡單的,只需要在查詢前后使用PageHelper的startPage和endPage方法即可,中間代碼的調用結果已經存在于Page的result中,如果你在一個返回一個結果的地方調用PageHelper,返回的結果仍然是一個List,取第一個值即可(我想沒人會在這種地方這么用,當然這樣也不出錯)。

另外在startPage和endPage中間的所有mybatis代碼都會被分頁,而且PageHelper只會保留最后一次的結果,因而使用時需要保證每次只在其中執行一個mybatis查詢,如果有多個分頁,請多次使用startPage和endPage。

由于這里只提供了Oracle的實現,所以我希望參考該分頁插件實現的其他數據庫的讀者也能將相應的代碼開源。

項目地址:http://xiazai.VeVB.COm/201612/yuanma/Mybatis_PageHelper_jb51.zip

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 涡阳县| 河南省| 崇文区| 吐鲁番市| 天柱县| 遂宁市| 德庆县| 永春县| 阿尔山市| 颍上县| 依安县| 涟水县| 哈巴河县| 阿瓦提县| 克拉玛依市| 吐鲁番市| 绥中县| 宁明县| 吐鲁番市| 雅江县| 天柱县| 临颍县| 化德县| 新津县| 奉贤区| 贞丰县| 庆元县| 湛江市| 邢台县| 武平县| 庆阳市| 马公市| 芦溪县| 盐池县| 外汇| 台中市| 巧家县| 宜春市| 广河县| 乐安县| 芜湖县|