分页是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表达式。