MyBatis 分頁之攔截器實現

  分頁是WEB程序中常見的功能,mybatis分頁實現與hibernate不一樣,相比hibernate,mybatis實現分頁更爲麻煩。mybatis實現分頁須要本身編寫(非邏輯分頁RowBounds),以mysql爲例,使用分頁時須要本身在mapper中的sql語句中添加LIMIT #{xx},#{xx}。這種方式不具有可重用性與可拓展性。mysql

  mybatis提供了plugins,plugins實現了攔截器的功能。它能夠攔截指定類中的方法,當指定的方法被執行時,mybatis就會自動攔截並完成相應邏輯。經過mybatis的plugins,就能夠實現自動分頁功能。git

  實現分析:攔截查詢語句,判斷該查詢語句是否須要添加分頁,修改原來的sql語句,查詢獲得的總記錄數github

  具體源碼在https://github.com/yuen666/mybatis-paginationsql

簡要思路

  編寫Interceptor,攔截StatementHandler中的prapare方法,在mybatis中,執行的是RoutingStatementHandler實現類。該類使用代理的方式來調用BaseStatementHandler。數據庫

  

  在每次使用查詢語句時,都會調用RoutingStatementHandler.prepare(...),該方法的實現以下:mybatis

  

  它調用了delegate的prepare,實現類爲BaseStatementHandler,源碼以下:app

  

  因爲每次查詢都調用該prepare方法,故能夠對RoutingStatementHandler的prepare進行攔截。該方法中擁有connection對象,經過connection對象也能夠鏈接數據庫查詢總記錄數,比較方便。spa

  關於sql語句的修改。在delegate中,即BaseStatementHandler中,擁有以下幾個域:hibernate

  

  其中,boundSql中包含了sql語句(boundSql.sql),因爲是protected類型,因此能夠採用反射的方式獲取原sql語句並設置新sql語句。3d

  總結下:

  1. 攔截StatementHandler的prepare方法
  2. 經過反射獲取delegate.boundSql.sql修改並設置
  3. 獲取參數connection並查詢中記錄數

 關於反射

  mybaits提供了MetaObject類,該類對反射進行封裝。能夠經過該類快速的實現獲取與設置delegate.boundSql.sql。

private Object getValue(StatementHandler statementHandler, String exp) {
    MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,
            SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
    return metaObject.getValue(exp);
}
private void setValue(StatementHandler statementHandler, String exp, Object obj) {
    MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,
            SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
    metaObject.setValue(exp, obj);
}

  其中的exp爲OGNL表達式。

相關文章
相關標籤/搜索