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

相关文章
相关标签/搜索