Mybatis source parsing --ResultSetHandler

ResultSetHandler

Is responsible for the database returns the result object is mapped to ResultSet

public interface ResultSetHandler {

//处理结果集,生成对应的结果对象集
  <E> List<E> handleResultSets(Statement stmt) throws SQLException;

//处理结果集,生成对应的游标对象集
  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;

//处理存储过程的输出参数
  void handleOutputParameters(CallableStatement cs) throws SQLException;

}

DefaultResultSetHandler

The default implementation ResultSetHandler implementation class analysis interface, after analysis are based on

ResultSetWrapper

DefaultResultSetHandler not directly used in getting ResultSet, but packaged as ResultSetWrapper for subsequent use, some of the metadata recorded ResultSetWrapper ResultSet and corresponding method of assisted, as each column ResultSet

  • Column name (constructor initializes)
  • java type (constructor initializes)
  • jdbc type (constructor initializes)
  • Set corresponding typeHandler
  • Column names explicitly mapped collection
  • Column name is not explicitly mapped (ie resultMap not set column mappings)
  • ……

loadMappedAndUnMappedColumnNames () traverses the ResultSet ColumnName column name specified in the mapping ResultMap comparison, was added to mappedMap / unmappedMap in, key column name prefix for the id and the resultMap

Simple mapping

handleResultSet () uses the specified or default ResultSetHandler the ResultSet, handleRowValues ​​() is a specific method, according to whether the method comprising two nested into handleRowValuesForNestedResultMap () and handleRowValuesForSimpleResultMap ().

Non-nested mapping

The core method handleRowValuesForSimpleResultMap ()

private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
      throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
    skipRows(rsw.getResultSet(), rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
      ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
      Object rowValue = getRowValue(rsw, discriminatedResultMap);
      storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
    }
  }

Executing the flowchart shown in FIG.

Here Insert Picture Description

Proceed as follows:

  1. The RowBounds in rows offset to locate the specified
  2. Detect whether there needs to be mapped records
  3. The mapping is determined using ResultMapId discriminator Discriminated objects returned ResultMap
  4. A row of the ResultSet mapping
    a. Create result object
    b. Determines whether to open the automatic mapping
    c. Automatically map columns are not explicitly mapped
    d. Mapped column explicitly mapped
  5. Save mapped object to the results obtained in ResultHandler

Results for storing objects resultHandler

skipRows

According to rowBounds ResultSet.next repeatedly invoked the offset () method to the specified record

shouldProcessMoreRows

Storing the results determined using DefaultResultContext objects, the number of objects is counted and the results, by comparing DefaultResultContext.isStopped () and the count rowBounds.limit () comparison results whether to continue mapping

resolveDiscriminatedResultMap

The Discriminated returned ResultMapId used to determine the mapping objects ResultMap

getRowValue
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
      }
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
  }
  1. createResultObject
    total of four scenarios

private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
      throws SQLException {
    final Class<?> resultType = resultMap.getType();
    final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    if (hasTypeHandlerForResultObject(rsw, resultType)) {
    //第一种
      return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
    } else if (!constructorMappings.isEmpty()) {
    //第二种
      return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
    //第三种
      return objectFactory.create(resultType);
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
    //第四种
      return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
  }

  • The first: The result set is only one, and there can be listed typeHandler resultType converting the value type, the first type of typeHandler get this object and the object using the direct conversion (e.g., only a check of age, back to a digital , directly converted to type int returned)
  • Second: ResultMap recorded in <Constructor>the node information, the object created by the reflection method of selecting suitable configuration
  • Third: Use the default constructor with no arguments, create objects with ObjectFactory
  • Fourth: by automatic mapping to find the appropriate constructor, we need to add @AutoMapConstructor annotation on the constructor. The method of construction parameters and results will be centralized in the same data sequence (the first corresponding to the first, second one corresponds to the second) match the type, if the same type to call the constructor, the properties of the object obtained value may be wrong, but property values ​​will overwrite errors later in the mapping process.
ApplyAutomaticMappings

For mapping relationship is not explicitly specified in ResultMap attributes (e.g., the specified directly ResultType), Mybatis accordance with the rules are matched automatically turn underlined hump, its matching process is as follows:

  1. Get the set of all column names are not explicitly mapped in from ResultSetWrapper
  2. Traversing a collection, and to specify the prefix is ​​removed to obtain the corresponding underlined attribute name transferred humps
  3. The setter method uses reflection attribute check for metaObject
  4. Find the corresponding type of typeHandler
  5. UnMappedColumnAutoMapping configuration objects (including listed, attribute name and the typeHandler)
  6. 5 traversal list used for setting values ​​reflective
applyPropertyMappings
  1. Get a set of all the column names explicitly mapped in from ResultSetWrapper
  2. Get PropertyResultMappings collection from the ResultMap
  3. getPropertyMappingValue () Gets the value of the attribute, and the value provided by reflection, there are three cases
  • For complex objects, the need for nesting process
  • For primitive types, used directly to obtain the value typeHandler
  • Multi-result sets the scene
storeObject

A record will be saved in the result object to ResultHandler.list, carried out mapping

Nested mapping

Core method handleRowValuesForNestedResultMap ()
the following steps:

  1. The RowBounds in rows offset to locate the specified

  2. Detect whether there needs to be mapped records

  3. The mapping is determined using ResultMapId discriminator Discriminated objects returned ResultMap

  4. By createKey () record is generated cacheKey

  5. Find cacheKey semi-finished products stored in the dictionary nestedResultObjects

  6. Detection ResultOrdered property

  7. getRowValue nested mapping process

    If the outer object does not exist ( nestedResultObjects.get() != null)

    a. Create result object
    b. determines whether to open the automatic mapping process to determine whether or not explicitly mapped column
    c. Disposal explicitly mapped column
    d. Place a result objects placed in the collection ancestorObjects
    e. call applyNestedResultMappings () processing the next layer nested mapping result objects obtained in this method will be injected into the outer ancestorObjects collection object, where the end of return
    f. removing the outer set of objects ancestorObjects
    g. of the object into a semi-finished product in nestedResultObjects

    If there is
    performed d, e, f Step

  8. Mapping is done, storeObject result objects placed in ResultHandler

createKey

Each ResultSet CacheKey will be created as a key in a HashMap presence of a nestedResultObjects, the map object is a semi-finished objects stored in the result of the processing priority set here Looking semifinished objects, if there are instructions for the current nested mapping, the current results need to be injected into the target layer (i.e., the semifinished object) to the properties.
How to ensure that external resultMap in the corresponding outer and inner layers are treated the same? That is the same as cacheKey?
cacheKey Create rules are as follows:

  1. ResuleMapId + <id>/<idArg>node corresponding to a value corresponding to the column name +
  2. ResultMap clearly mapped column names and corresponding values
  3. If ResultType for the Map type, all the column names and corresponding values
  4. If not ResultType type Map, and the column name corresponding to the value is not mapped

The above rules created its outer CacheKey CacheKey then combined into a globally unique CacheKey

ResultOrdered

When the value is true, each outer layer mapping object processing ends next outer nested object will be nestedResultObjects case, memory can be saved, to avoid out of memory appears in the middle

Lazy loading

Certain properties of the object when in use will be loaded into memory, Mybatis dynamic form of proxy and return a proxy object lazy loading properties of the object, the proxy object performs the database load to get the real data in use.
Loading the delay for the nested query, nested query and queries are two main different statemetn, defined in resultMap. When the main query results are mapped in the end, the resolution mapping nested query to determine the current position would still delay the execution of nested queries based on the delay loaded configuration

Delayed loaded configuration:

  1. resultMap explicitly configured fetchType property, whether the property is decided according to delay loading
  2. mybatis-config.xml the <setting name="lazyLoadingEnabled" value = "true">opening delay loading switch
  3. mybatis-config.xml in <setting name="aggressiveLazyLoading" value = "false">time when there is a true lazy properties obtained loading, loading all delay property will be loaded, default false
ResultLoaderMap和ResultLoader

ResultLoader save all the information to conduct a lazy loading, including configuration objects, Executor, SQL statements, type, CacheKey, with its core approach is loadResult () method, which uses lazy loading Executor execute SQL statement and return an object

ResultLoaderMap used loadMap field (HashMap <String, LoadPair>) stored object attributes and their corresponding loading delay ResultLoader objects, key attribute name loadAll uppercase () and load () method are provided which call LoadPair.load () method, the final point ResultLoader.loadResult () method

ResultLoaderMap proxy object will hold departure list of methods and lazy loading, if the current method in the list, then delayed loading.

Reflect lazy loading

In applyPropertyMappings () method call getPropertyMappingValue () getting the property value, detects whether lazy loading, default JavasistProxyFactory create a proxy object

as the picture shows
Here Insert Picture Description

Published 98 original articles · won praise 9 · views 10000 +

Guess you like

Origin blog.csdn.net/Mutou_ren/article/details/102794613