美文网首页
MyBatis源码分析(4)- SqlSession接口增删改查

MyBatis源码分析(4)- SqlSession接口增删改查

作者: 32d27b231c78 | 来源:发表于2018-02-09 16:29 被阅读61次

上篇分析到了SimpleExecutor接口, 这个接口中的doUpdate,doQuery方法是Executor体系中最终的实现。 本节分析下Executor中具体的逻辑

1. SimpleExecutor接口

1.1 doUpdate, doQuery的实现

  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }

  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 handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return stmt;
  }

上面的3行代码就是由BaseExecutor类中的query,update调用到SimpleExecutor的方法。可以看到对于doUpdate,doQuery两个方法都有如下几步:

  • Configuration类中生成一个对应的StatementHandler
  • 获取一个JDBC连接,然后调用handlerprepare方法,该方法事实上是调用的connection.createStatement创建的连接。handler接口下面讲述
  • 然后调用handler的对应query,update方法
  • 再返回数据给BaseExecutor中的query, update方法当中

显而易见,StatementHandler接口实际承担了Statement的生成以及query, update的操作。

2. StatementHandler接口

2.1 整体结构

mybatis-source-analyze-statement.png

2.2 调用分析

2.2.1 介绍

StatementHandler接口的继承链与Executor接口的非常相似,都是包含一个委托类,一个抽象基类以及3哥实现类。调用方式有些许不同:

  • StatementHandlerquery, update的调用最终会传到SimpleStatementHandler, PrepareStementHandler, CallableStatementHandler中的一个
  • RoutingStatementHandler的构造函数起到了工厂的作用,它根据statement的类型决定生成SimpleStatementHandler, PrepareStementHandler, CallableStatementHandler哪一个实例。
    下面分别看下这3个类的实现方式

2.2.2 SimpleStatementHandler

  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();
    statement.execute(sql);
    return resultSetHandler.<E>handleResultSets(statement);
  }
  public int update(Statement statement) throws SQLException {
    String sql = boundSql.getSql();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    int rows;
    if (keyGenerator instanceof Jdbc3KeyGenerator) {
      statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
      rows = statement.getUpdateCount();
      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    } else if (keyGenerator instanceof SelectKeyGenerator) {
      statement.execute(sql);
      rows = statement.getUpdateCount();
      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    } else {
      statement.execute(sql);
      rows = statement.getUpdateCount();
    }
    return rows;
  }

2.2.3 PrepareStementHandler

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.<E> handleResultSets(ps);
  }
public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    int rows = ps.getUpdateCount();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
  }

2.2.4 CallableStementHandler

public int update(Statement statement) throws SQLException {
    CallableStatement cs = (CallableStatement) statement;
    cs.execute();
    int rows = cs.getUpdateCount();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);
    resultSetHandler.handleOutputParameters(cs);
    return rows;
  }
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    CallableStatement cs = (CallableStatement) statement;
    cs.execute();
    List<E> resultList = resultSetHandler.<E>handleResultSets(cs);
    resultSetHandler.handleOutputParameters(cs);
    return resultList;
  }

2.2.5 总结

上面3个类结合JDBC的API一看就知道是怎么回事,这3个类就是对JDBC的SQL执行的一层封装。
所以到目前为止,我们看到了SqlSession接口调用mapper xml的执行链:sqlsession -> executor -> statementhandler,最终会根据具体SQL的类型调用JDBC的三种statement类型来处理实际业务。 MappedStatement封装了mapper xml中声明的每一个SQL。 StatementHandler封装了JDBC操作。 Executor封装了mapper xml缓存以及执行,批量执行。
合理的策略模式、抽象基类 非常完美的阐释了java中的OO思维。

相关文章

网友评论

      本文标题:MyBatis源码分析(4)- SqlSession接口增删改查

      本文链接:https://www.haomeiwen.com/subject/yexqtftx.html