mybatis执行sql过程 - 969251639/study GitHub Wiki

下面分析一个查询和一个更新的流程
mybtais获取到session后就可以对sql进行操作

public class DefaultSqlSession implements SqlSession {
  ...
  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
  @Override
  public int update(String statement, Object parameter) {
    try {
      dirty = true;
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
  ...
}

1. 查询
获取mapper信息

MappedStatement ms = configuration.getMappedStatement(statement);

这样便知道了要执行的sql,参数,返回值等基础信息
然后通过执行器(默认为SIMPLE)调用查询

return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter);//绑定sql
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);//根据mapper,参数,分页,sql生成缓存key
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);//查询
 }

  @SuppressWarnings("unchecked")
  @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ...
    list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
    ...
  }
  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ...
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    ...
  }

  @Override
  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);//创建一个handler,拦截扩展用
      stmt = prepareStatement(handler, ms.getStatementLog());//通过数据库连接获取statement
      return handler.<E>query(stmt, resultHandler);//执行sql查询
    } finally {
      closeStatement(stmt);
    }
  }

  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);//打开数据库连接
    stmt = handler.prepare(connection, transaction.getTimeout());获取statement
    handler.parameterize(stmt);
    return stmt;
  }

要注意的是上面在获取Statement时是通过handler去拿的

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);//返回代理对象
    return statementHandler;
  }

默认生成的是RoutingStatementHandler

public class RoutingStatementHandler implements StatementHandler {

  private final StatementHandler delegate;

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }
  @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    return delegate.prepare(connection, transactionTimeout);
  }
   ...
}

所以具体生成那种statement在构造RoutingStatementHandler的时候就已经确定了,默认是PREPARED

public final class MappedStatement {
...
public static class Builder {
    private MappedStatement mappedStatement = new MappedStatement();
    public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) {
        ...
        mappedStatement.statementType = StatementType.PREPARED;
        ...
    }
    ...
}

所以最后执行查询的是PreparedStatementHandler

    return handler.<E>query(stmt, resultHandler);//执行sql查询

最好的查询就是用原生的jdbc的PreparedStatement去查询数据库,最后封装成结果返回

public class PreparedStatementHandler extends BaseStatementHandler {
  ...
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.<E> handleResultSets(ps);
  }
  ...
}


**2. 更新**  
更新那里会先将参数dirty置为true,表示数据已有变动,用来控制事务的提交和回滚   

@Override public int update(String statement, Object parameter) { ... dirty = true; ... } private boolean isCommitOrRollbackRequired(boolean force) { //如果是非自动提交且数据已有变更 或者 强制提交(默认false) 返回true return (!autoCommit && dirty) || force; }

@Override public void commit() { commit(false); }

@Override public void commit(boolean force) { try { executor.commit(isCommitOrRollbackRequired(force)); dirty = false; } catch (Exception e) { throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } @Override public void rollback() { rollback(false); }

@Override public void rollback(boolean force) { try { executor.rollback(isCommitOrRollbackRequired(force)); dirty = false; } catch (Exception e) { throw ExceptionFactory.wrapException("Error rolling back transaction. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }


然后获取mapper信息

MappedStatement ms = configuration.getMappedStatement(statement);

这样便知道了要执行的sql,参数,返回值等基础信息  
然后通过执行器(默认为SIMPLE)调用更新  

return executor.update(ms, wrapCollection(parameter));


@Override public int update(MappedStatement ms, Object parameter) throws SQLException { ... return doUpdate(ms, parameter); } @Override 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); } }

流程跟查一样,需要获取handler,发然拿到Statement,最后执行update   

public class PreparedStatementHandler extends BaseStatementHandler { ... @Override 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; } ... }

⚠️ **GitHub.com Fallback** ⚠️