美文网首页
Mybatis源码分析4--StatementHandler

Mybatis源码分析4--StatementHandler

作者: zhuke | 来源:发表于2017-09-05 19:31 被阅读0次

MyBatis sql执行过程如下图所示:

MyBatis sql执行过程

SqlSession将执行过程委托给Executor,Executor又将执行过程交给StatementHandler具体执行。

下面我们对StatementHandler的设计进行具体分析。

StatementHandler类继承结构
  • SimpleStatementHandler:用于处理Statement对象的数据库操作

  • PreparedStatementHandler:用于处理PreparedStatement对象的数据库操作

  • CallableStatementHandler:用于处理CallableStatement对象的数据库操作(存储过程)

  • RoutingStatementHandler:用于创建上面三种Handler的策略类


BaseStatementHandler

在BaseStatementHandler中定义了生成Statement对象的基本算法结构,而具体生成Statement的类型和算法,则由子类自行决定:

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      //由子类自行决定要生成的Statement类型和算法
      statement = instantiateStatement(connection);
      setStatementTimeout(statement, transactionTimeout);
      setFetchSize(statement);
      return statement;
    } catch (SQLException e) {
      closeStatement(statement);
      throw e;
    } catch (Exception e) {
      closeStatement(statement);
      throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
  }

SimpleStatementHandler

SimpleStatementHandler是利用Statement对象进行数据库操作的相关算法定义。由instantiateStatement方法生成一个Statement对象。

protected Statement instantiateStatement(Connection connection) throws SQLException {
    if (mappedStatement.getResultSetType() != null) {
      return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.createStatement();
    }
  }

因为Statement不支持?形式的参数占位符,所以其parameterize方法时空的:

public void parameterize(Statement statement) throws SQLException {
    // N/A
  }

PreparedStatementHandler

PreparedStatementHandler定义了生成一个PrepareStatement对象,和对PrepareStatement对象进行参数填充的方法。

protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
      } else {
        return connection.prepareStatement(sql, keyColumnNames);
      }
    } else if (mappedStatement.getResultSetType() != null) {
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.prepareStatement(sql);
    }
  }
public void parameterize(Statement statement) throws SQLException {
    //将参数填充委托给parameterHandler进行处理
    parameterHandler.setParameters((PreparedStatement) statement);
  }

CallableStatementHandler

CallableStatementHandler定义了生成一个CallableStatement对象,和对CallableStatement对象进行参数填充的方法。

protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getResultSetType() != null) {
      return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.prepareCall(sql);
    }
  }

ParameterHandler

ParameterHandler负责对Statement的参数进行填充和处理。MyBatis提供了一个默认实现DefaultParameterHandler。

public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
      for (int i = 0; i < parameterMappings.size(); i++) {
        ParameterMapping parameterMapping = parameterMappings.get(i);
        if (parameterMapping.getMode() != ParameterMode.OUT) {
          Object value;
          String propertyName = parameterMapping.getProperty();
          if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
            value = boundSql.getAdditionalParameter(propertyName);
          } else if (parameterObject == null) {
            value = null;
          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
            value = parameterObject;
          } else {
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            value = metaObject.getValue(propertyName);
          }
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          JdbcType jdbcType = parameterMapping.getJdbcType();
          if (value == null && jdbcType == null) {
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
          } catch (TypeException e) {
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          } catch (SQLException e) {
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          }
        }
      }
    }
  }

StatementHandler的创建过程

Executor每次执行select & update,都会创建一个StatementHandler对象。

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

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    //根据配置的类型创建不同的StatementHandler
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

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());
    }

  }

StatementType参数可以在SQL Mapper文件中进行配置:

<select id="select" resultType="mybatis.bean.User" statementType="STATEMENT">
        select * from user_info where id = #{id}
    </select>

StatementType有三种不同的类型:

public enum StatementType {
  STATEMENT, PREPARED, CALLABLE
}

默认为PREPARED


总结

  • SimpleStatementHandler
Statement stm = conn.createStatement()
return stm.execute(sql);
  • PreparedStatementHandler
PreparedStatement pstm = conn.prepareStatement(sql);
pstm.setString(1, "Hello");
return pstm.execute();
  • CallableStatementHandler
CallableStatement cs = conn.prepareCall("{call pr_add(?,?,?)}");
cs.registerOutParameter(3, Types.INTEGER);
cs.setInt(1, 10);
cs.setString(2, "Hello");
cs.execute();
return cs.getInt(3);
  • RoutingStatementHandler

根据mapper文件中配置的type类型创建相应的上述StatementHandler类型

相关文章

网友评论

      本文标题:Mybatis源码分析4--StatementHandler

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