分頁是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
總結下:
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表達式。