Análisis del código fuente de Mybaits (ocho) Explicación detallada de StatementHandler

    Análisis del código fuente de Mybaits (ocho) Explicación detallada de StatementHandler


    Resumen : StatementHandler es el principal responsable de manejar la interacción de Statement entre MyBatis y JDBC. En términos generales, es responsable de operar la interacción entre el objeto Statement y la base de datos. El proceso de ejecución se basa principalmente en ParameterHandler y ResultSetHandler para el enlace de parámetros y el enlace de la clase de entidad de resultado.

Uno, introducción a la clase

1. El nivel de clase de
    
    StatementHandler StatementHandler : la interfaz de nivel superior, que define métodos como actualizar, consultar, parametrizar, preparar, etc.
    
    BaseStatementHandler : Implementación básica, responsable de crear ParameterHandler y ResultSetHandler.
    
    PreparedStatementHandler : implementación de declaración preparada,
    
    SimpleStatementHandler : implementación de declaración simple,
    
    CallableStatementHandler : implementación de procedimiento almacenado.
    
    RoutingStatementHandler : empaquetado de enrutamiento, según diferentes tipos para crear diferentes implementaciones como delegado del método de implementación real a llamar.
    
    2. Constructor El constructor de
      StatementHandler pasa principalmente algunos parámetros necesarios en la ejecución real y crea procesamiento de parámetros y procesadores de resultados.

  protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
	    this.configuration = mappedStatement.getConfiguration();
	    this.executor = executor;
	    this.mappedStatement = mappedStatement;
	    this.rowBounds = rowBounds;
	
	    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
	    this.objectFactory = configuration.getObjectFactory();
	
	    if (boundSql == null) { 
	      generateKeys(parameterObject);
	      boundSql = mappedStatement.getBoundSql(parameterObject);
	    }
	    this.boundSql = boundSql; 
	    // 创建参数处理器
	    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
	    // 创建结果处理器
	    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
	  }

    En segundo lugar, el proceso de ejecución

    1. Ejecución de instrucciones SQL y etapa de análisis de parámetros

     1) Método de línea principal
 

 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 (会根据statement类型创建不同的StatementHandler)
	      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
	      // 预处理语句
	      stmt = prepareStatement(handler, ms.getStatementLog());
	      // StatementHandler的query
	      return handler.<E>query(stmt, resultHandler);
	    } finally {
	      closeStatement(stmt);
	    }
	  }
	
	  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
	    Statement stmt;
	    Connection connection = getConnection(statementLog);
	    // 调用StatementHandler的prepare方法
	    stmt = handler.prepare(connection);
	    // 调用hanlder的parameterize方法
	    handler.parameterize(stmt);
	    return stmt;
	  }
	  

     2) Preparar el método de StatementHandler

     El método de preparación de StatementHandler se implementa en BaseStatementHandler y se llama al método instantiateStatement

  public Statement prepare(Connection connection) throws SQLException {
	    ErrorContext.instance().sql(boundSql.getSql());
	    Statement statement = null;
	    try {
	      statement = instantiateStatement(connection);
	      setStatementTimeout(statement);
	      setFetchSize(statement);
	      return statement;
	    } 
	  }
	  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) {
	      // 预编译sql传入不同的resultSet的类型 (遍历方向)
	      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
	    } else { // 预编译sql
	      return connection.prepareStatement(sql);
	    }
	  }

     El método prepare realmente llama a la encapsulación de connection.prepareStatement

 3) el método parametrizar de StatementHandler

 public void parameterize(Statement statement) throws SQLException {
	    // 调用parameterHandler设置参数
	    parameterHandler.setParameters((PreparedStatement) statement);
	  }
	 
	   public void setParameters(PreparedStatement ps) throws SQLException {
	    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
	    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
	    if (parameterMappings != null) {
	      // 遍历parameterMappings
	      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)) {
	            // 从Additional中取属性值
	            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 jdbcType = parameterMapping.getJdbcType();
	          if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
	          // preparedStatement设置参数
	          typeHandler.setParameter(ps, i + 1, value, jdbcType);
	        }
	      }
	    }
	  }	

    4). Después de que se establecen los parámetros, se debe realizar el procesamiento del valor de retorno. Continuar desde el controlador de proceso de la línea principal. <E> consulta (stmt, resultHandler).

	 PreparedStatementHandler 的实现。
	 public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
	    PreparedStatement ps = (PreparedStatement) statement;
	    ps.execute(); // 强转成预编译语句,执行execute然后交由结果处理器处理结果。
	    return resultSetHandler.<E> handleResultSets(ps); 
	  }
	
	 SimpleStatementHandler 的实现
	
	  public <E> List<E> query(Statement statement, ResultHandler resultHandler)throws SQLException {
	    String sql = boundSql.getSql();
	    statement.execute(sql); //直接执行sql
	    return resultSetHandler.<E>handleResultSets(statement);
	  }


 2. Etapa de procesamiento del valor de retorno

 Como puede ver en lo anterior, el procesamiento del valor de retorno lo maneja principalmente resultSetHandler.

 

 

El proceso de procesamiento del conjunto de resultados es más complicado, ¡así que lo explicaré por separado en el seguimiento!
¡fin!

 

 


    

Supongo que te gusta

Origin blog.csdn.net/shuixiou1/article/details/113732826
Recomendado
Clasificación