Mybatis-KeyGenerator源码解析

Mybatis3.5.1源码分析

  1. Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
  2. Mybatis-Configuration源码解析
  3. Mybatis-事务对象源码解析
  4. Mybatis-数据源源码解析
  5. Mybatis缓存策略源码解析
  6. Mybatis-DatabaseIdProvider源码解析
  7. Mybatis-TypeHandler源码解析
  8. Mybatis-Reflector源码解析
  9. Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
  10. Mybatis-Mapper各类标签封装类源码解析
  11. Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
  12. Mybatis-MapperAnnotationBuilder源码分析
  13. [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
  14. Mybatis-LanguageDriver源码解析
  15. Mybatis-SqlSource源码解析
  16. Mybatis-SqlNode源码解析
  17. Mybatis-KeyGenerator源码解析
  18. Mybatis-Executor源码解析
  19. Mybatis-ParameterHandler源码解析
  20. Mybatis-StatementHandler源码解析
  21. Mybatis-DefaultResultSetHandler(一)源码解析
  22. Mybatis-DefaultResultSetHandler(二)源码解析
  23. Mybatis-ResultHandler,Cursor,RowBounds 源码分析
  24. Mybatis-MapperProxy源码解析
  25. Mybatis-SqlSession源码解析
  26. Mybatis-Interceptor源码解析

KeyGenerator

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.keygen;

import java.sql.Statement;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;

/**
 * @author Clinton Begin
 */
public interface KeyGenerator {

  /**
   * 执行之前运行
   * @param executor
   * @param ms
   * @param stmt
   * @param parameter
   */
  void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter);

  /**
   * 执行之后运行
   * @param executor
   * @param ms
   * @param stmt
   * @param parameter
   */
  void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter);

}

Jdbc3KeyGenerator

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.keygen;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.ArrayUtil;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.defaults.DefaultSqlSession.StrictMap;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

/**
 * 主要用于数据库的自增主键,比如 MySQL、PostgreSQL;会将执行SQL后从Statemenet中获取主键放到参数对象对应的属性里
 * @author Clinton Begin
 * @author Kazuki Shimizu
 */
public class Jdbc3KeyGenerator implements KeyGenerator {

  /**
   * A shared instance.
   *
   * @since 3.4.3
   */
  public static final Jdbc3KeyGenerator INSTANCE = new Jdbc3KeyGenerator();

  private static final String MSG_TOO_MANY_KEYS = "Too many keys are generated. There are only %d target objects. "
      + "You either specified a wrong 'keyProperty' or encountered a driver bug like #1523.";

  @Override
  public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    // do nothing
  }

  @Override
  public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    processBatch(ms, stmt, parameter);
  }

  /**
   * 将 {@code stmt} 返回的主键赋值到 {@code parameter}
   * @param ms  Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param stmt 执行SQL 语句并返回它所生成结果的对象。
   * @param parameter 参数对象
   */
  public void processBatch(MappedStatement ms, Statement stmt, Object parameter) {
    /**
     * keyProperties:
     *  MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,
     *  默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
     */
    final String[] keyProperties = ms.getKeyProperties();
    //如果属性名数组为null 或者 属性名数组没有元素
    if (keyProperties == null || keyProperties.length == 0) {
      //结束方法
      return;
    }
    /**
     * getGeneratedKeys:该方法获取由于执行此Statement对象而创建的所有自动生成的键。
     * 如果此Statement对象没有生成任何键,则返回空的ResultSet对象。
     */
    try (ResultSet rs = stmt.getGeneratedKeys()) {
      //获取结果集的元信息
      final ResultSetMetaData rsmd = rs.getMetaData();
      //获取mybatis全局配置信息
      final Configuration configuration = ms.getConfiguration();
      //如果结果集的返回列名数量小于配置属性名数组长度
      if (rsmd.getColumnCount() < keyProperties.length) {
        // Error? 不作任何处理
      } else {
        //根据 parameter 的类型构建AssignKey对象,然后将 rs 的结果赋值到 parameter 的元素中
        assignKeys(configuration, rs, rsmd, keyProperties, parameter);
      }
    } catch (Exception e) {
      throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);
    }
  }

  /**
   * 根据 {@code parameter} 的类型构建AssignKey对象,然后将 {@code rs} 的结果赋值到 {@code parameter} 的元素中
   * @param configuration mybatis全局配置新
   * @param rs 结果集
   * @param rsmd 结果集元信息
   * @param keyProperties 属性名数组
   * @param parameter 参数对象
   */
  @SuppressWarnings("unchecked")
  private void assignKeys(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd, String[] keyProperties,
      Object parameter) throws SQLException {
    //StrictMap,ParamMap:其功能甚至连代码都是一致的,都是HashMap的子类,都是对获取集合没有元素时会抛出异常。【个人认为是不是冗余了?】
    //如果参数对象是StrictMap,ParamMap的实例时
    if (parameter instanceof ParamMap || parameter instanceof StrictMap) {
      // Multi-param or single param with @Param
      //根据 parameter 构建KeyAssigner对象,然后将rs的对应数据赋值到 parameter 的对应的元素中
      assignKeysToParamMap(configuration, rs, rsmd, keyProperties, (Map) parameter);

      //如果参数对象是ArrayList实例,且parameter是有元素的 且 获取parameter的第一个元素属于ParamMap实例
    } else if (parameter instanceof ArrayList && !((ArrayList) parameter).isEmpty()
        && ((ArrayList) parameter).get(0) instanceof ParamMap) {
      // Multi-param or single param with @Param in batch operation
      //构建AssignKey对象,将 rs 的结果赋值到 paramMapList 的元素中
      assignKeysToParamMapList(configuration, rs, rsmd, keyProperties, ((ArrayList>) parameter));
    } else {
      // Single param without @Param
      //构建AssignKey对象,将 rs 的结果赋值到 parameter 的元素中,如果parameter不是集合,会自动将parameter转换成集合
      assignKeysToParam(configuration, rs, rsmd, keyProperties, parameter);
    }
  }

  /**
   * 构建AssignKey对象,将 {@code rs} 的结果赋值到 {@code parameter} 的元素中,如果parameter不是集合,会自动将parameter
   * 转换成集合
   * @param configuration mybatis全局配置信息
   * @param rs 结果集
   * @param rsmd 结果集元素
   * @param keyProperties 属性名数组
   * @param parameter 参数对象
   * @throws SQLException
   */
  private void assignKeysToParam(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
      String[] keyProperties, Object parameter) throws SQLException {
    //将parameter转换成Collection对象
    Collection params = collectionize(parameter);
    //如果params是空集合
    if (params.isEmpty()) {
      //结束方法
      return;
    }
    //定义一个分配者集合
    List assignerList = new ArrayList<>();
    //遍历属性数组
    for (int i = 0; i < keyProperties.length; i++) {
      //构建分配者对象饭后添加到分配者集合
      assignerList.add(new KeyAssigner(configuration, rsmd, i + 1, null, keyProperties[i]));
    }
    //获取参数对象的迭代器
    Iterator iterator = params.iterator();
    //遍历结果集
    while (rs.next()) {
      //如果iterator没有下一个元素,即结果集还有结果,但是参数对象集合已经没有元素可以接收结果了
      if (!iterator.hasNext()) {
        //抛出异常,并描述
        throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, params.size()));
      }
      //获取下一个参数对象
      Object param = iterator.next();
      //变量分配者进行分配,将rs的对应columnPosition位置的列数据赋值到param对应的propertyName中
      assignerList.forEach(x -> x.assign(rs, param));
    }
  }

  /**
   * 构建AssignKey对象,将 {@code rs} 的结果赋值到 {@code paramMapList} 的元素中
   * @param configuration mybatis全局配置新
   * @param rs 结果集
   * @param rsmd 结果集元信息
   * @param keyProperties 配置的属性名数组
   * @param paramMapList ArrayList类型的参数对象
   * @throws SQLException
   */
  private void assignKeysToParamMapList(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
      String[] keyProperties, ArrayList> paramMapList) throws SQLException {
    //获取paramMapList的迭代器
    Iterator> iterator = paramMapList.iterator();
    //初始化一个分配器集合
    List assignerList = new ArrayList<>();
    //计数器,表示已分配的结果数
    long counter = 0;
    //遍历结果集
    while (rs.next()) {
      //如果ParamMapList没有下一个元素,即结果集还有结果,但是参数对象集合已经没有元素可以接收结果了
      if (!iterator.hasNext()) {
        throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, counter));
      }
      //获取参数对象的元素
      ParamMap paramMap = iterator.next();
      //如果分配器集合为空
      if (assignerList.isEmpty()) {
        //遍历配置的属性数组
        for (int i = 0; i < keyProperties.length; i++) {
          //从ParamMap中构建KeyAssigner并赋值到新的entry中,然后将entry的值添加到分配器集合里
          assignerList
              .add(getAssignerForParamMap(configuration, rsmd, i + 1, paramMap, keyProperties[i], keyProperties, false)
                  .getValue());
        }
      }
      //遍历分配器集合,将rs的对应columnPosition位置的列数据赋值到paramMap对应的propertyName中
      assignerList.forEach(x -> x.assign(rs, paramMap));
      counter++;
    }
  }

  /**
   * 根据 {@code paramMap} 构建KeyAssigner对象,然后将 {@code rs} 的对应数据赋值到 {@code paramMap} 的对应的元素中
   * @param configuration Mybatis的全局配置信息
   * @param rs 结果集
   * @param rsmd 结果集元信息
   * @param keyProperties 配置的属性名数组
   * @param paramMap ParamMap类型或者StrictMap类型的参数对象
   */
  private void assignKeysToParamMap(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
      String[] keyProperties, Map paramMap) throws SQLException {
    //如果参数对象没有元素
    if (paramMap.isEmpty()) {
      //结束方法
      return;
    }
    //新建一个分配映射集合
    Map, List>> assignerMap = new HashMap<>();
    //遍历属性名数组
    for (int i = 0; i < keyProperties.length; i++) {
      //从ParamMap中构建KeyAssigner并赋值到新的entry中
      Entry entry = getAssignerForParamMap(configuration, rsmd, i + 1, paramMap, keyProperties[i],
          keyProperties, true);
      /**
       * 下面代码与下面注释的代码的简化版:
       *
       * //获取entry的键名对应assignerMap的对象
       * String key=entry.getKey();
       * //初始化iteratorPair
       * Entry, List> iteratoirPair=null;
       * //如果key为null
       * if(key==null){
       *    //获取paramMap对应key的值,并转换成Collection对象
       *    Object value=paramMap.get(key);
       *    Iterator iterator=collectionize(value).iterator();
       *    //初始化一个存储KeyAssigner集合
       *    List keyAssignerList=new ArrayList<>();
       *    //构成iterator实例
       *    iteratorirPair=enrty(iterator,keyAssignerList);
       * }
       */
      Entry, List> iteratorPair = assignerMap.computeIfAbsent(entry.getKey(),
          k -> entry(collectionize(paramMap.get(k)).iterator(), new ArrayList<>()));
      //将entry存储的keyAssigner存放到iteratorPair的集合里
      iteratorPair.getValue().add(entry.getValue());
    }
    //计数器,表示已分配的结果数
    long counter = 0;
    //遍历结果集元素
    while (rs.next()) {
      //遍历assigenMap的值集合
      for (Entry, List> pair : assignerMap.values()) {
        //如果参数对象的键对象已经没有下一个了,这里的应该只是取iterator的第一个元素而已,而这里判断他是否存在第一个元素,不存在就抛出异常
        if (!pair.getKey().hasNext()) {
          throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, counter));
        }
        //获取下一个参数对象的健对象
        Object param = pair.getKey().next();
        //分配,将rs的对应columnPosition位置的列数据赋值到param对应的propertyName中
        pair.getValue().forEach(x -> x.assign(rs, param));
      }
      counter++;
    }
  }

  /**
   * 从ParamMap中构建KeyAssigner并赋值到新的entry中
   * @param config Mybatis全局配置信息
   * @param rsmd 结果集元信息
   * @param columnPosition 列名位置
   * @param paramMap ParamMap类型或者StrictMap类型的参数对象
   * @param keyProperty 配置的属性名
   * @param keyProperties 配置的属性名数组
   * @param omitParamName 是否忽略参数名称
   */
  private Entry getAssignerForParamMap(Configuration config, ResultSetMetaData rsmd,
      int columnPosition, Map paramMap, String keyProperty, String[] keyProperties, boolean omitParamName) {
    //获取paramMap的值集合,再获取值集合的接口流对象,对值集合进行去重处理后,得到去重后的数量,如果去重后的数量为1,singleParam为true
    //singleParam表示只有一个参数值
    boolean singleParam = paramMap.values().stream().distinct().count() == 1;
    //因为keyProperty有可能是'order.name'形式的,firstDot表示属性名的第一个点
    int firstDot = keyProperty.indexOf('.');
    //如果没有不存在第一个点
    if (firstDot == -1) {
      //如果只有一个参数值
      if (singleParam) {
        //从单一的{@code paramMap}中构建KeyAssigner并保存到新的Entry中
        return getAssignerForSingleParam(config, rsmd, columnPosition, paramMap, keyProperty, omitParamName);
      }
      //如果不是只有一个参数值
      throw new ExecutorException("Could not determine which parameter to assign generated keys to. "
          + "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
          + "Specified key properties are " + ArrayUtil.toString(keyProperties) + " and available parameters are "
          + paramMap.keySet());
    }
    //截取前面的字符串为参数名
    String paramName = keyProperty.substring(0, firstDot);
    //如果参数对象中有这个参数名
    if (paramMap.containsKey(paramName)) {
      //如果忽略参数名,aragParamName为null;否则aragPramName为singleParamName
      String argParamName = omitParamName ? null : paramName;
      //截取属性名点后面的字符串为参数键属性名
      String argKeyProperty = keyProperty.substring(firstDot + 1);
      //构建KeyAssigner并赋值到新的entry中
      return entry(paramName, new KeyAssigner(config, rsmd, columnPosition, argParamName, argKeyProperty));

      //如果只有一个参数值
    } else if (singleParam) {
      //从单一的{@code paramMap}中构建KeyAssigner并保存到新的Entry中
      return getAssignerForSingleParam(config, rsmd, columnPosition, paramMap, keyProperty, omitParamName);
    } else {
      //如果参数对象中没有这个参数名且不只有一个参数值时
      throw new ExecutorException("Could not find parameter '" + paramName + "'. "
          + "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
          + "Specified key properties are " + ArrayUtil.toString(keyProperties) + " and available parameters are "
          + paramMap.keySet());
    }
  }

  /**
   * 从单一的{@code paramMap}中构建KeyAssigner并保存到新的Entry中
   * @param config Mybatis全局配置信息
   * @param rsmd 结果集元信息
   * @param columnPosition 列名位置
   * @param paramMap ParamMap类型或者StrictMap类型的参数对象
   * @param keyProperty 配置的属性名
   * @param omitParamName 是否忽略参数名称
   */
  private Entry getAssignerForSingleParam(Configuration config, ResultSetMetaData rsmd,
      int columnPosition, Map paramMap, String keyProperty, boolean omitParamName) {
    // Assume 'keyProperty' to be a property of the single param. 假设关键属性的单一参数的属性。;
    //获取paramMap唯一的键名
    String singleParamName = nameOfSingleParam(paramMap);
    //如果忽略参数名,aragParamName为null;否则aragPramName为singleParamName
    String argParamName = omitParamName ? null : singleParamName;
    //构建KeyAssigner并赋值到新的entry中,
    return entry(singleParamName, new KeyAssigner(config, rsmd, columnPosition, argParamName, keyProperty));
  }

  /**
   * 获取参数映射唯一健名
   * @param paramMap 参数映射
   * @return 参数映射唯一健名
   */
  private static String nameOfSingleParam(Map paramMap) {
    // There is virtually one parameter, so any key works.
    //获取paramMap的键名Set,通过迭代器,获取第一个键名并返回
    return paramMap.keySet().iterator().next();
  }

  /**
   * 将 {@code param} 转换成 Collection对象
   * @param param 参数对象
   * @return 如果 {@code param} 不是Collection对象,都会转换成ArrayList对象;否则直接返回 {@code param} ;
   */
  private static Collection collectionize(Object param) {
    //如果param本来就是Collection的实现类,
    if (param instanceof Collection) {
      //不需要转换,执行返回
      return (Collection) param;
      //如果param是Object数组的实现了
    } else if (param instanceof Object[]) {
      //将param转换成ArrayList对象
      return Arrays.asList((Object[]) param);
    } else {
      //如果是普通java类,构建成ArrayList对象
      return Arrays.asList(param);
    }
  }

  /**
   * 构建Entry
   * @param key 键名
   * @param value 值对象
   */
  private static  Entry entry(K key, V value) {
    // Replace this with Map.entry(key, value) in Java 9.
    return new AbstractMap.SimpleImmutableEntry<>(key, value);
  }

  /**
   * 键名分配者
   */
  private class KeyAssigner {
    /**
     * mybatis全局配置信息
     */
    private final Configuration configuration;
    /**
     * 结果集元信息
     */
    private final ResultSetMetaData rsmd;
    /**
     * TypeHandler注册器
     */
    private final TypeHandlerRegistry typeHandlerRegistry;
    /**
     * 列名位置
     */
    private final int columnPosition;
    /**
     * 参数名
     */
    private final String paramName;
    /**
     * 属性名
     */
    private final String propertyName;
    /**
     * TypeHandler
     */
    private TypeHandler typeHandler;

    /**
     *
     * @param configuration mybatis全局配置信息
     * @param rsmd 结果集元信息
     * @param columnPosition 列名位置
     * @param paramName 参数名
     * @param propertyName 属性名
     */
    protected KeyAssigner(Configuration configuration, ResultSetMetaData rsmd, int columnPosition, String paramName,
        String propertyName) {
      super();
      this.configuration = configuration;
      this.rsmd = rsmd;
      this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
      this.columnPosition = columnPosition;
      this.paramName = paramName;
      this.propertyName = propertyName;
    }

    /**
     * 分配,将rs的对应columnPosition位置的列数据赋值到param对应的propertyName中
     * @param rs 结果集
     * @param param 参数对象
     */
    protected void assign(ResultSet rs, Object param) {
      //如果参数名不为null
      if (paramName != null) {
        // If paramName is set, param is ParamMap 如果设置了参数名称,参数是参数映射;
        //从param获取paramName的值重新赋值给param
        param = ((ParamMap) param).get(paramName);
      }
      //构建param的元对象
      MetaObject metaParam = configuration.newMetaObject(param);
      try {
        //如果typeHandler不为null
        if (typeHandler == null) {
          //如果param元对象存在propertyName的setter方法
          if (metaParam.hasSetter(propertyName)) {
            //获取propertyName的setter方法的属性类型
            Class propertyType = metaParam.getSetterType(propertyName);
            //根据属性类型,当前列名位置的jdbc类型取得对应的TypeHandler对象并赋值给typeHandler
            typeHandler = typeHandlerRegistry.getTypeHandler(propertyType,
                JdbcType.forCode(rsmd.getColumnType(columnPosition)));
          } else {
            //如果param元对象不存在propertyName的setter方法
            throw new ExecutorException("No setter found for the keyProperty '" + propertyName + "' in '"
                + metaParam.getOriginalObject().getClass().getName() + "'.");
          }
        }
        //如果typeHandler还是为null
        if (typeHandler == null) {
          // Error? 忽略
        } else {
          //获取结果对象
          Object value = typeHandler.getResult(rs, columnPosition);
          //将结果对赋值到parm对应的propertyName中
          metaParam.setValue(propertyName, value);
        }
      } catch (SQLException e) {
        throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e,
            e);
      }
    }
  }
}

SelectKeyGenerator

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.keygen;

import java.sql.Statement;
import java.util.List;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.RowBounds;

/**
 * 用于执行selectKey标签的SQL,将结果赋值到参数对象对应的属性中
 * @author Clinton Begin
 * @author Jeff Butler
 */
public class SelectKeyGenerator implements KeyGenerator {

  /**
   * selectKeyId后缀
   */
  public static final String SELECT_KEY_SUFFIX = "!selectKey";
  /**
   * 执行之前运行标记,通过这个标记使得keyStatement只执行一次
   */
  private final boolean executeBefore;
  /**
   * selectKey的MappedStatement对象
   */
  private final MappedStatement keyStatement;

  /**
   *
   * @param keyStatement selectKey的MappedStatement对象
   * @param executeBefore 业务SQL执行之前运行标记
   */
  public SelectKeyGenerator(MappedStatement keyStatement, boolean executeBefore) {
    this.executeBefore = executeBefore;
    this.keyStatement = keyStatement;
  }

  @Override
  public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    //如果是业务SQL执行之前执行
    if (executeBefore) {
      //执行 ms 的SQL,然后将结果赋值 parameter 对应的配置属性中
      processGeneratedKeys(executor, ms, parameter);
    }
  }

  @Override
  public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    //如果不是业务SQL执行之前执行
    if (!executeBefore) {
      //执行 ms 的SQL,然后将结果赋值 parameter 对应的配置属性中
      processGeneratedKeys(executor, ms, parameter);
    }
  }

  /**
   * 执行 {@code ms} 的SQL,然后将结果赋值 {@code parameter} 对应的配置属性中
   * @param executor 执行器
   * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类,在这里指的select标签
   * @param parameter 参数对象
   */
  private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
    try {
      //如果参数对象不为null 且 selectKey的MappedStatement对象不为null 且 selectKey的配置的属性名不为null
      if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
        //获取selectKey配置的属性数组
        String[] keyProperties = keyStatement.getKeyProperties();
        //获取mybatis全局配置信息
        final Configuration configuration = ms.getConfiguration();
        //构建参数对象的元对象
        final MetaObject metaParam = configuration.newMetaObject(parameter);
        //如果属性数组不为null
        if (keyProperties != null) {
          // Do not close keyExecutor. 不要关闭KeyExecutor
          // The transaction will be closed by parent executor. 事务会被关闭通过父级执行器
          //新建一个SimpleExecutor对象,用于执行SQL
          Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
          /**
           * Executor.NO_RESULT_HANDLER: 表示没有结果处理器的标记
           * RowBounds.DEFAULT:Mybatis的分页类的默认对象,表示从0条记录开始,到Integer.MAX_VALUE的最大记录数
           */
          //执行查询SQL得到结果对象集合
          List values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
          //如果没有结果对象
          if (values.size() == 0) {
            //抛出异常
            throw new ExecutorException("SelectKey returned no data.");
            //如果有超过一个结果对象
          } else if (values.size() > 1) {
            //抛出异常
            throw new ExecutorException("SelectKey returned more than one value.");
            //只有一个结果对象
          } else {
            //构建结果对象的元对象
            MetaObject metaResult = configuration.newMetaObject(values.get(0));
            //如果配置的属性数组的元素只有一个
            if (keyProperties.length == 1) {
              //如果结果对象存在这个keyProperties[0]的Getter方法
              if (metaResult.hasGetter(keyProperties[0])) {
                //将结果对象keyProperties[0]的属性值赋值到参数对象keyProperties[0]属性值里
                setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
              } else {
                // no getter for the property - maybe just a single value object    没有属性getter方法—也许只有一个值对象;
                // so try that 所以尝试赋值
                //将结果对象的第一个元素赋值到metaParam的keyProperties里
                setValue(metaParam, keyProperties[0], values.get(0));
              }
            } else {
              // 处理多个属性的情况,将结果对象对配置的列名属性值赋值到参数对象对应配置的属性属性值里
              handleMultipleProperties(keyProperties, metaParam, metaResult);
            }
          }
        }
      }
    } catch (ExecutorException e) {
      throw e;
    } catch (Exception e) {
      throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
    }
  }

  /**
   * 处理多个属性的情况,将结果对象对配置的列名属性值赋值到参数对象对应配置的属性属性值里
   * @param keyProperties 属性集合
   * @param metaParam 参数元对象
   * @param metaResult 结果元对象
   */
  private void handleMultipleProperties(String[] keyProperties,
      MetaObject metaParam, MetaObject metaResult) {
    //获取配置的列名数组
    String[] keyColumns = keyStatement.getKeyColumns();
    //没有配置列名数组或者列名数组是空数组
    if (keyColumns == null || keyColumns.length == 0) {
      // no key columns specified, just use the property names 没有列名被指定是,只能使用属性名
      //遍历属性数组
      for (String keyProperty : keyProperties) {
        //将结果对象keyProperties的属性值赋值到参数对象keyProperties属性值里
        setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));
      }
      //如果有配置列名数组且列名数组不是空数组时
    } else {
      //如果配置的列名数组长度跟配置的属性数组长度不一致时
      if (keyColumns.length != keyProperties.length) {
        //抛出异常
        throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
      }
      //遍历属性数组
      for (int i = 0; i < keyProperties.length; i++) {
        /**
         * 注意这里由于i是同时当作列名数组的游标和属性数组的游标,直接取出相应位置元素进行赋值,并有判断它们是否对应,所以这里在mapper.xml
         * 的列名数组和属性数组时顺序一定要一致,否则会出现属性和列名不对应而导致赋值错误
         */
        //将结果对象keyProperties[i]的属性值赋值到参数对象keyProperties[i]属性值里
        setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
      }
    }
  }

  /**
   * 将 {@code value} 赋值到 {@code metaParam} 的 {@code property} 里
   * @param metaParam 参数元对象
   * @param property 属性名
   * @param value 属性值
   */
  private void setValue(MetaObject metaParam, String property, Object value) {
    //如果参数元对象存在property的setter方法
    if (metaParam.hasSetter(property)) {
      //将 value 赋值到 metaParam 的 property 里
      metaParam.setValue(property, value);
      //如果不存setter方法
    } else {
      //抛出异常
      throw new ExecutorException("No setter found for the keyProperty '" + property + "' in " + metaParam.getOriginalObject().getClass().getName() + ".");
    }
  }
}

 
 

NoKeyGenerator

/**
 *    Copyright 2009-2017 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.keygen;

import java.sql.Statement;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;

/**
 * 什么事情都不干,里面是空实现方法
 * @author Clinton Begin
 * @author Kazuki Shimizu
 */
public class NoKeyGenerator implements KeyGenerator {

  /**
   * A shared instance.
   * @since 3.4.3
   */
  public static final NoKeyGenerator INSTANCE = new NoKeyGenerator();

  @Override
  public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    // Do Nothing
  }

  @Override
  public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    // Do Nothing
  }

}

你可能感兴趣的:(Mybatis-KeyGenerator源码解析)