Mybatis的分页插件

@Intercepts(@Signature(type = StatementHandler.class,
  method = "prepare",
  args = {Connection.class, Integer.class}))
@SuppressWarnings("all")
public class PageInterceptor implements Interceptor {
  /**
   * 执行到这里
   *
   * @param invocation
   * @return
   * @throws Throwable
   */
  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    //1 检测是否满足分页条件
    //1.1 带上分页参数
    StatementHandler target = (StatementHandler) invocation.getTarget();
    //1.2sql包
    BoundSql boundSql = target.getBoundSql();
    Object parameterObject = boundSql.getParameterObject();
    Page page = null;
    if (parameterObject instanceof Page) {
      page = (Page) parameterObject;
    } else if (parameterObject instanceof Map) {
      page = (Page) ((Map) parameterObject).values().stream().filter(v -> v instanceof Page).findFirst().orElse(null);
    }
    if (page == null){
      return invocation.proceed();
    }
    if (page != null) {
      //设置总行数 select count(1) from user;
      int count = selectCount(invocation);
      page.setTotal(count);
    }
    //修改原有的sql select * from user offset 0,limit 50;
    String newSql = String.format("%s limit %s offset %s",boundSql.getSql(),page.getSize(),page.getOffset());
    SystemMetaObject.forObject(boundSql).setValue("sql",newSql);
    //直接放行
    return invocation.proceed();
  }

  private int selectCount(Invocation invocation) throws SQLException {
    int count = 0;
    StatementHandler taget = (StatementHandler) invocation.getTarget();
    String countSql = String.format("select count(*) from (%s) as _page", taget.getBoundSql());
    Connection conneciton = (Connection) invocation.getArgs()[0];
    PreparedStatement preparedStatement = conneciton.prepareStatement(countSql);
    //设置参数
    taget.getParameterHandler().setParameters(preparedStatement);
    ResultSet resultSet = preparedStatement.executeQuery();
    if (resultSet.next()){
      count = resultSet.getInt(0);
    }
    resultSet.close();
    preparedStatement.close();
    return count;
  }


  @Override
  public Object plugin(Object target) {
    return null;
  }

  @Override
  public void setProperties(Properties properties) {

  }
}

mybatis分页插件

 SqlSession执行增删改查都是委托给Executor完成的

 Executor主要完成以下几项内容:

  1. 处理缓存,包括一级缓存和二级缓存
  2. 获取数据库连接
  3. 创建Statement或者PrepareStatement对象
  4. 访问数据库执行SQL语句
  5. 处理数据库返回结果   

CachingExecutor

        CachingExecutor用于处理二级缓存,如果缓存中不存在要查询的数据,那么将查询请求委托给其他的Executor。如果是执行SQL的增删改,那么CachingExecutor将清空二级缓存

BaseExecutor

当调用该类的查询方法时,先查看一级缓存中是否已经有数据,如果有则直接从缓存获取,如果没有调用子类的查询方法从数据库中获取。
当调用该类的update方法(mybatis将delete和insert认为是update,统一调用该类update方法)时,BaseExecutor将一级缓存清空,然后调用子类对应的增删改方法。
调用执行rollback/commit方法时,该类清空一级缓存

SimpleExecutor

SimpleExecutor继承自BaseExecutor,该类比较简单。
当执行增删改查时,该类获取数据库连接,创建PrepareStatement或者Statement对象,执行SQL语句,最后将数据库返回结果转化为设定的对象

public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      // 获取StatementHandler对象
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      // 调用prepareStatement()方法,创建Statement对象,并进行设置参数等操作
      stmt = prepareStatement(handler, ms.getStatementLog());
      // 调用StatementHandler对象的query()方法执行查询操作
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

SimpleExecutor基本是按照标注JDBC流程执行SQL语句获得返回结果

BatchExecutor

当执行查询时,BatchExecutor与SimpleExecutor的处理逻辑是一样的。不同的是执行更新方法(mybatis认为delete和insert都是update)。执行更新方法时,BatchExecutor不是直接执行SQL语句,而是将其放到批次里面,等到提交的时候一起执行

public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
    final Configuration configuration = ms.getConfiguration();
    final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
    final BoundSql boundSql = handler.getBoundSql();
    final String sql = boundSql.getSql();
    final Statement stmt;
    if (sql.equals(currentSql) && ms.equals(currentStatement)) {
      int last = statementList.size() - 1;
      stmt = statementList.get(last);
      applyTransactionTimeout(stmt);
      handler.parameterize(stmt);//fix Issues 322
      BatchResult batchResult = batchResultList.get(last);
      batchResult.addParameterObject(parameterObject);
    } else {
      Connection connection = getConnection(ms.getStatementLog());
      stmt = handler.prepare(connection, transaction.getTimeout());
      handler.parameterize(stmt);    //fix Issues 322
      currentSql = sql;
      currentStatement = ms;
      statementList.add(stmt);
      batchResultList.add(new BatchResult(ms, sql, parameterObject));
    }
  // handler.parameterize(stmt);
    handler.batch(stmt);
    return BATCH_UPDATE_RETURN_VALUE;
  }

ReuseExecutor

ReuseExecutor从名字可以看出该类主要特点是复用。它复用的是Statement对象或者PreparedStatement对象。
该类中有一个属性statementMap,如下面代码所示,key是SQL语句,value是Statement对象。每次执行首先根据SQL语句查询statementMap,如果有对应的Statement对象,则直接使用该Statement对象,如果没有,则创建新的Statement对象,然后将其和SQL语句添加到statementMap

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值