文章目录

  • 1、举个case-向数据库插入单个实体对象
  • 2、核心类和核心方法
    • 2.1、Part1​【解析】:zap:解析Mapper接口、@Insert注解和其他入参。
      • 2.1.1、MapperProxy源码分析
      • 2.1.2、MapperMethod源码分析
      • 2.1.3、ParamNameResolver源码分析
    • 2.2、Part2【执行】:zap:SqlSession的会话处理,获取映射会话,执行查询
      • 2.2.1、DefaultSqlSession源码分析
      • 2.2.2、Configuration源码分析
      • 2.2.3、CachingExecutor源码分析
      • 2.2.4、MappedStatement源码分析
      • 2.2.5、BoundSql源码分析
      • 2.2.6、BaseExecutor源码分析
      • 2.2.7、SimpleExecutor源码分析
      • 2.2.8、RoutingStatementHandler和PreparedStatementHandler源码分析
    • 2.5、Part4​【结果集处理】:zap:结果集处理封装
      • 2.5.1、DefaultResultSetHandler源码分析
      • 2.5.2、Jdbc3KeyGenerator源码分析

1、举个case-向数据库插入单个实体对象

下面我们分析一个最常用的mapper接口,向数据库插入单个实体对象的源码实现逻辑。

省略配置文件…因为重点在于插入源码,先回顾下我们应用app服务端开发熟悉的配置mybatis过程。

 //加载MapperConfig.xml的配置文件
final String resource = "org/apache/ibatis/builder/MapperConfig.xml";
//根据配置文件获取字符流final Reader reader = Resources.getResourceAsReader(resource);
//根据字符流构建SqlSessionFactorySqlSessionFactory  sqlMapper = new SqlSessionFactoryBuilder().build(reader);
//获取全局核心配置类Configuration configuration = new Configuration(sqlMapper.getConfiguration().getEnvironment());//为全局配置添加需要的Mapper接口configuration.addMapper(AuthorMapperWithAnnotation.class);//创建SQL会话工厂SqlSessionFactory sqlMapperWithAnnotation = new DefaultSqlSessionFactory(configuration);//获取SQL会话SqlSession sqlSession =  sqlMapperWithAnnotation.openSession();//从会话中获取绑定好的mapper接口信息AuthorMapperWithAnnotation mapper = sqlSession.getMapper(AuthorMapperWithAnnotation.class);//执行mapper接口的实现方法//执行插入会话Author expected = new Author(500, "wolf_love666:\"test\"", "******", "liuxiaocheng@somewhere.com", "Something...", null);mapper.insertAuthorWithPlaceholder(expected);//期待返回正确的数据assertEquals(500,expected.getId());

如果你细心的话,就会发现与上面的查询我们这里只更改了mapper接口的方法,因为本节主要是讲该插入的源码。


这里依然举例注解方式。

/*** @author liuxiaocheng* @create 2020/3/28  9:43 上午*/
public interface AuthorMapperWithAnnotation {// TODO: 2020/3/28 by wolf_love666 for study source code@InsertProvider(type =AuthorProvider.class,method = "insertAuthorWithPlaceholder")void insertAuthorWithPlaceholder(Author author);class AuthorProvider{// 插入带有占位符预编译的会话SQLpublic String insertAuthorWithPlaceholder(Author author){return new SQL(){{INSERT_INTO("Author").VALUES("id,username,password,email,bio","#{id},#{username},#{password},#{email},#{bio}");}}.toString();}}
}

通常意义上我们的服务端开发已经结束了,接下来只需要去数据库看下数据是否正确就OK了,而今天我们讲的内容是需要看下mybatis框架是如何执行插入的。

这是完整的mybatis执行时序图。

2、核心类和核心方法

2.1、Part1​【解析】⚡️解析Mapper接口、@Insert注解和其他入参。

MapperProxy(根据动态代理执行目标mapper接口)

MapperMethod(根据@Insert找到对应的Update方法、根据方法签名确定返回参数)

ParamNameResolver(根据args入参解析属性入参,获取对应的动态值)

2.1.1、MapperProxy源码分析

/*** Mapper接口代理--真正的mapper执行类*/
public class MapperProxy<T> implements InvocationHandler, Serializable {...省略本次无关内容...//mapper接口的执行@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {//object类直接执行if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);//缓存的执行器执行} else {return cachedInvoker(proxy, method, args).invoke(proxy, method, args, sqlSession);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}}//缓存的执行器private MapperMethodInvoker cachedInvoker(Object proxy, Method method, Object[] args) throws Throwable {try {return methodCache.computeIfAbsent(method, m -> {if (m.isDefault()) {try {//jdk8和jdk9的默认方法执行if (privateLookupInMethod == null) {return new DefaultMethodInvoker(getMethodHandleJava8(method));} else {return new DefaultMethodInvoker(getMethodHandleJava9(method));}} catch (IllegalAccessException | InstantiationException | InvocationTargetException| NoSuchMethodException e) {throw new RuntimeException(e);}} else {//返回声明的方法执行器return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));}});} catch (RuntimeException re) {Throwable cause = re.getCause();throw cause == null ? re : cause;}}//Java9获取方法处理器private MethodHandle getMethodHandleJava9(Method method)throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {final Class<?> declaringClass = method.getDeclaringClass();return ((Lookup) privateLookupInMethod.invoke(null, declaringClass, MethodHandles.lookup())).findSpecial(declaringClass, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()),declaringClass);}//Java8获取方法处理器private MethodHandle getMethodHandleJava8(Method method)throws IllegalAccessException, InstantiationException, InvocationTargetException {final Class<?> declaringClass = method.getDeclaringClass();return lookupConstructor.newInstance(declaringClass, ALLOWED_MODES).unreflectSpecial(method, declaringClass);}//Mapper方法执行器接口interface MapperMethodInvoker {Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable;}...省略本次无关内容...
}

2.1.2、MapperMethod源码分析

/*** Mapper的方法 add by wolf_love666*/
public class MapperMethod {//命令private final SqlCommand command;//方法签名private final MethodSignature method;//映射的接口和方法和全局配置public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {this.command = new SqlCommand(config, mapperInterface, method);this.method = new MethodSignature(config, mapperInterface, method);}//执行sqlSession和参数public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {...省略本次无关内容...//插入case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}//更新case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}//删除case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}...省略本次无关内容...default:throw new BindingException("Unknown execution method for: " + command.getName());}if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {throw new BindingException("Mapper method '" + command.getName()+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");}return result;}//行数结果private Object rowCountResult(int rowCount) {final Object result;//无返回值if (method.returnsVoid()) {result = null;//int返回类型} else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {result = rowCount;//long返回类型} else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {result = (long)rowCount;//boolean返回类型} else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {result = rowCount > 0;} else {//其他不支持throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());}return result;}
}

2.1.3、ParamNameResolver源码分析

/*** 参数名字解析器 add by wolf_love666*/
public class ParamNameResolver {public static final String GENERIC_NAME_PREFIX = "param";...省略本次无关内容.../*** 返回一个没有名称的非特殊参数。 使用命名规则来命名多个参数。 除了默认名称外,此方法还添加了通用名称(param1,param2,* ...)。*/public Object getNamedParams(Object[] args) {//获取对象final int paramCount = names.size();if (args == null || paramCount == 0) {return null;} else if (!hasParamAnnotation && paramCount == 1) {return args[names.firstKey()];} else {final Map<String, Object> param = new ParamMap<>();int i = 0;for (Map.Entry<Integer, String> entry : names.entrySet()) {param.put(entry.getValue(), args[entry.getKey()]);//添加通用的参数名字final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);// 确保带有@Param注解参数的不被重写if (!names.containsValue(genericParamName)) {param.put(genericParamName, args[entry.getKey()]);}i++;}return param;}}
}

2.2、Part2【执行】⚡️SqlSession的会话处理,获取映射会话,执行查询

  • DefaultSqlSession(主要完成从全局配置获取会话,和执行绑定的查询)
  • Configuration(全局配置-来源于加载全局配置文件的时候初始化的信息,也就是说如果你的mapper接口是在启动服务之后新加的,那么这里找不到则会报错。)
  • CachingExecutor(默认开启的是session会话缓存,也就是一级缓存,所以会走缓存执行器,如果是Object类的话则直接处理属于特殊情况)
  • MappedStatement(映射绑定的会话)
  • BoundSql(绑定传入的sql)
  • BaseExecutor(抽象的公共执行器)
  • SimpleExecutor(简单的执行器执行)
  • RoutingStatementHandler和PreparedStatementHandler会话处理器

2.2.1、DefaultSqlSession源码分析


public class DefaultSqlSession implements SqlSession {//全局配置private final Configuration configuration;//执行器private final Executor executor;//是否自动提交private final boolean autoCommit;//是否脏数据private boolean dirty;//游标结果集private List<Cursor<?>> cursorList;//构造函数public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {this.configuration = configuration;this.executor = executor;this.dirty = false;this.autoCommit = autoCommit;}//构造函数public DefaultSqlSession(Configuration configuration, Executor executor) {this(configuration, executor, false);}...省略本次无关内容(上一节的查询方法函数)...//插入会话@Overridepublic int insert(String statement) {return insert(statement, null);}//插入会话@Overridepublic int insert(String statement, Object parameter) {return update(statement, parameter);}//更新会话@Overridepublic int update(String statement) {return update(statement, null);}//更新会话@Overridepublic 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();}}//删除会话@Overridepublic int delete(String statement) {return update(statement, null);}//删除会话@Overridepublic int delete(String statement, Object parameter) {return update(statement, parameter);}...省略本次无关内容(提交刷新回滚)...//封装集合private Object wrapCollection(final Object object) {if (object instanceof Collection) {StrictMap<Object> map = new StrictMap<>();map.put("collection", object);if (object instanceof List) {map.put("list", object);}return map;} else if (object != null && object.getClass().isArray()) {StrictMap<Object> map = new StrictMap<>();map.put("array", object);return map;}return object;}//严格mappublic static class StrictMap<V> extends HashMap<String, V> {private static final long serialVersionUID = -5741767162221585340L;@Overridepublic V get(Object key) {if (!super.containsKey(key)) {throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + this.keySet());}return super.get(key);}}}

2.2.2、Configuration源码分析

/**
*全局配置类 add by wolf_love666
*/
public class Configuration { ...省略本次无关内容...//获取映射的会话根据会话ID
public MappedStatement getMappedStatement(String id) {return this.getMappedStatement(id, true);}//获取映射的会话根据会话IDpublic MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {//是否需要验证不匹配的会话if (validateIncompleteStatements) {//构建所有会话验证buildAllStatements();}//获取映射的会话根据会话IDreturn mappedStatements.get(id);}/** 解析缓存中所有未处理的语句节点。建议一旦添加了所有映射器,便调用此方法,因为它提供了快速失败语句验证*/protected void buildAllStatements() {parsePendingResultMaps();if (!incompleteCacheRefs.isEmpty()) {synchronized (incompleteCacheRefs) {incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null);}}if (!incompleteStatements.isEmpty()) {synchronized (incompleteStatements) {incompleteStatements.removeIf(x -> {x.parseStatementNode();return true;});}}if (!incompleteMethods.isEmpty()) {synchronized (incompleteMethods) {incompleteMethods.removeIf(x -> {x.resolve();return true;});}}}//解析等待的结果map集private void parsePendingResultMaps() {if (incompleteResultMaps.isEmpty()) {return;}synchronized (incompleteResultMaps) {boolean resolved;IncompleteElementException ex = null;do {resolved = false;Iterator<ResultMapResolver> iterator = incompleteResultMaps.iterator();while (iterator.hasNext()) {try {iterator.next().resolve();iterator.remove();resolved = true;} catch (IncompleteElementException e) {ex = e;}}} while (resolved);if (!incompleteResultMaps.isEmpty() && ex != null) {// At least one result map is unresolvable.throw ex;}}}...省略本次无关内容...}


Configuration的内部实现类StrictMap


//严格的map内部实现类protected static class StrictMap<V> extends HashMap<String, V> {...省略本次无关内容...//获取全局配置的属性对应的值@Overridepublic V get(Object key) {V value = super.get(key);if (value == null) {throw new IllegalArgumentException(name + " does not contain value for " + key);}if (value instanceof Ambiguity) {throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name+ " (try using the full name including the namespace, or rename one of the entries)");}return value;}//内部语义不明的类protected static class Ambiguity {final private String subject;public Ambiguity(String subject) {this.subject = subject;}public String getSubject() {return subject;}
}private String getShortName(String key) {final String[] keyParts = key.split("\\.");return keyParts[keyParts.length - 1];
}}

2.2.3、CachingExecutor源码分析


public class CachingExecutor implements Executor {//代表执行器private final Executor delegate;//事务缓存管理private final TransactionalCacheManager tcm = new TransactionalCacheManager();//初始化构造器,执行器就是本身。public CachingExecutor(Executor delegate) {this.delegate = delegate;delegate.setExecutorWrapper(this);}//获取执行器的事务@Overridepublic Transaction getTransaction() {return delegate.getTransaction();}//关闭前强制是否回滚或者提交,最后执行器关闭@Overridepublic void close(boolean forceRollback) {try {//issues #499, #524 and #573if (forceRollback) {tcm.rollback();} else {tcm.commit();}} finally {delegate.close(forceRollback);}}//是否执行器被关闭@Overridepublic boolean isClosed() {return delegate.isClosed();}//如果有必要刷新缓存,执行器更新会话操作@Overridepublic int update(MappedStatement ms, Object parameterObject) throws SQLException {flushCacheIfRequired(ms);return delegate.update(ms, parameterObject);}...省略本次无关内容(刷新,提交回滚等操作)...//确保没有外来参数的缓存 否则不支持,比如字段有自己添加的private void ensureNoOutParams(MappedStatement ms, BoundSql boundSql) {if (ms.getStatementType() == StatementType.CALLABLE) {for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {if (parameterMapping.getMode() != ParameterMode.IN) {throw new ExecutorException("Caching stored procedures with OUT params is not supported.  Please configure useCache=false in " + ms.getId() + " statement.");}}}}//创建缓存key@Overridepublic CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {return delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql);}//是否缓存@Overridepublic boolean isCached(MappedStatement ms, CacheKey key) {return delegate.isCached(ms, key);}//延迟加载@Overridepublic void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) {delegate.deferLoad(ms, resultObject, property, key, targetType);}//清除本地缓存@Overridepublic void clearLocalCache() {delegate.clearLocalCache();}//如果有必要 刷新缓存 事务缓存管理清空缓存private void flushCacheIfRequired(MappedStatement ms) {Cache cache = ms.getCache();if (cache != null && ms.isFlushCacheRequired()) {tcm.clear(cache);}}//设置执行器包装器,这个方法应该从来不会被调用@Overridepublic void setExecutorWrapper(Executor executor) {throw new UnsupportedOperationException("This method should not be called");}}

2.2.4、MappedStatement源码分析


public final class MappedStatement {//资源private String resource;//全局配置private Configuration configuration;//idprivate String id;//拉取数量private Integer fetchSize;//超时private Integer timeout;//会话类型private StatementType statementType;//结果集类型private ResultSetType resultSetType;//sql源private SqlSource sqlSource;//缓存private Cache cache;//参数映射private ParameterMap parameterMap;//结果集合private List<ResultMap> resultMaps;//是否有必要刷新缓存private boolean flushCacheRequired;//是否使用缓存private boolean useCache;//结果是否有序private boolean resultOrdered;//sql命令类型private SqlCommandType sqlCommandType;//是否生成主键private KeyGenerator keyGenerator;//key属性集合private String[] keyProperties;//key列集合private String[] keyColumns;//是否有嵌套结果集合private boolean hasNestedResultMaps;//数据库IDprivate String databaseId;//会话日志private Log statementLog;//语言驱动private LanguageDriver lang;//结果集private String[] resultSets;//映射会话MappedStatement() {// constructor disabled}//内部构建类public static class Builder {//映射会话private MappedStatement mappedStatement = new MappedStatement();//构建器public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) {mappedStatement.configuration = configuration;mappedStatement.id = id;mappedStatement.sqlSource = sqlSource;mappedStatement.statementType = StatementType.PREPARED;mappedStatement.resultSetType = ResultSetType.DEFAULT;mappedStatement.parameterMap = new ParameterMap.Builder(configuration, "defaultParameterMap", null, new ArrayList<>()).build();mappedStatement.resultMaps = new ArrayList<>();mappedStatement.sqlCommandType = sqlCommandType;//Jdbc3KeyGenerator是生成key的主要实现mappedStatement.keyGenerator = configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;String logId = id;if (configuration.getLogPrefix() != null) {logId = configuration.getLogPrefix() + id;}mappedStatement.statementLog = LogFactory.getLog(logId);//获取默认的脚本语言实例mappedStatement.lang = configuration.getDefaultScriptingLanguageInstance();}//映射资源public Builder resource(String resource) {mappedStatement.resource = resource;return this;}//映射IDpublic String id() {return mappedStatement.id;}//参数映射public Builder parameterMap(ParameterMap parameterMap) {mappedStatement.parameterMap = parameterMap;return this;}//结果集public Builder resultMaps(List<ResultMap> resultMaps) {mappedStatement.resultMaps = resultMaps;for (ResultMap resultMap : resultMaps) {mappedStatement.hasNestedResultMaps = mappedStatement.hasNestedResultMaps || resultMap.hasNestedResultMaps();}return this;}//拉取数量public Builder fetchSize(Integer fetchSize) {mappedStatement.fetchSize = fetchSize;return this;}//超时时间public Builder timeout(Integer timeout) {mappedStatement.timeout = timeout;return this;}//会话类型public Builder statementType(StatementType statementType) {mappedStatement.statementType = statementType;return this;}//结果集类型public Builder resultSetType(ResultSetType resultSetType) {mappedStatement.resultSetType = resultSetType == null ? ResultSetType.DEFAULT : resultSetType;return this;}//缓存public Builder cache(Cache cache) {mappedStatement.cache = cache;return this;}//是否有必要刷新缓存public Builder flushCacheRequired(boolean flushCacheRequired) {mappedStatement.flushCacheRequired = flushCacheRequired;return this;}//是否使用缓存public Builder useCache(boolean useCache) {mappedStatement.useCache = useCache;return this;}//是否结果有序public Builder resultOrdered(boolean resultOrdered) {mappedStatement.resultOrdered = resultOrdered;return this;}//是否生成主键public Builder keyGenerator(KeyGenerator keyGenerator) {mappedStatement.keyGenerator = keyGenerator;return this;}//key属性public Builder keyProperty(String keyProperty) {mappedStatement.keyProperties = delimitedStringToArray(keyProperty);return this;}//key列public Builder keyColumn(String keyColumn) {mappedStatement.keyColumns = delimitedStringToArray(keyColumn);return this;}//数据库IDpublic Builder databaseId(String databaseId) {mappedStatement.databaseId = databaseId;return this;}//语言驱动public Builder lang(LanguageDriver driver) {mappedStatement.lang = driver;return this;}//结果集public Builder resultSets(String resultSet) {mappedStatement.resultSets = delimitedStringToArray(resultSet);return this;}/*** 不再建议使用* @deprecated Use {@link #resultSets}*/@Deprecatedpublic Builder resulSets(String resultSet) {mappedStatement.resultSets = delimitedStringToArray(resultSet);return this;}//构建返回会话public MappedStatement build() {assert mappedStatement.configuration != null;assert mappedStatement.id != null;assert mappedStatement.sqlSource != null;assert mappedStatement.lang != null;mappedStatement.resultMaps = Collections.unmodifiableList(mappedStatement.resultMaps);return mappedStatement;}}//属性的get方法,没有set防止外部破坏内部构建public KeyGenerator getKeyGenerator() {return keyGenerator;}public SqlCommandType getSqlCommandType() {return sqlCommandType;}public String getResource() {return resource;}public Configuration getConfiguration() {return configuration;}public String getId() {return id;}public boolean hasNestedResultMaps() {return hasNestedResultMaps;}public Integer getFetchSize() {return fetchSize;}public Integer getTimeout() {return timeout;}public StatementType getStatementType() {return statementType;}public ResultSetType getResultSetType() {return resultSetType;}public SqlSource getSqlSource() {return sqlSource;}public ParameterMap getParameterMap() {return parameterMap;}public List<ResultMap> getResultMaps() {return resultMaps;}public Cache getCache() {return cache;}public boolean isFlushCacheRequired() {return flushCacheRequired;}public boolean isUseCache() {return useCache;}public boolean isResultOrdered() {return resultOrdered;}public String getDatabaseId() {return databaseId;}public String[] getKeyProperties() {return keyProperties;}public String[] getKeyColumns() {return keyColumns;}public Log getStatementLog() {return statementLog;}public LanguageDriver getLang() {return lang;}public String[] getResultSets() {return resultSets;}/*** 不建议使用* @deprecated Use {@link #getResultSets()}*/@Deprecatedpublic String[] getResulSets() {return resultSets;}public BoundSql getBoundSql(Object parameterObject) {BoundSql boundSql = sqlSource.getBoundSql(parameterObject);List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings == null || parameterMappings.isEmpty()) {boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);}// check for nested result maps in parameter mappings (issue #30)for (ParameterMapping pm : boundSql.getParameterMappings()) {String rmId = pm.getResultMapId();if (rmId != null) {ResultMap rm = configuration.getResultMap(rmId);if (rm != null) {hasNestedResultMaps |= rm.hasNestedResultMaps();}}}return boundSql;}//根据逗号分割返回数组private static String[] delimitedStringToArray(String in) {if (in == null || in.trim().length() == 0) {return null;} else {return in.split(",");}}}

2.2.5、BoundSql源码分析


/*** 在已经执行一些动态内容之后,从{@link SqlSource} 获取实际的SQL。* SQL可能有占位符,并且参数映射有序 对于每个参数另外的信息(至少是从输入的对象读取值)* 可能也有另外的参数通过动态语言创建 比如循环或者绑定*/
public class BoundSql {//sqlprivate final String sql;//参数映射private final List<ParameterMapping> parameterMappings;//参数对象private final Object parameterObject;//附加参数private final Map<String, Object> additionalParameters;//元参数private final MetaObject metaParameters;//绑定SQL构造器public BoundSql(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Object parameterObject) {this.sql = sql;this.parameterMappings = parameterMappings;this.parameterObject = parameterObject;this.additionalParameters = new HashMap<>();this.metaParameters = configuration.newMetaObject(additionalParameters);}//获取SQLpublic String getSql() {return sql;}//获取参数映射public List<ParameterMapping> getParameterMappings() {return parameterMappings;}//获取参数对象public Object getParameterObject() {return parameterObject;}//是否有附加参数public boolean hasAdditionalParameter(String name) {String paramName = new PropertyTokenizer(name).getName();return additionalParameters.containsKey(paramName);}//设置附加参数--存放元参数信息public void setAdditionalParameter(String name, Object value) {metaParameters.setValue(name, value);}//获取附加参数public Object getAdditionalParameter(String name) {return metaParameters.getValue(name);}
}

2.2.6、BaseExecutor源码分析


public abstract class BaseExecutor implements Executor {//日志private static final Log log = LogFactory.getLog(BaseExecutor.class);//事务protected Transaction transaction;//执行器包装器protected Executor wrapper;//并发队列,延迟加载protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;//永久的本地缓存protected PerpetualCache localCache;//永久的本地外放参数缓存protected PerpetualCache localOutputParameterCache;//配置对象--全局很重要protected Configuration configuration;//查询栈protected int queryStack;//是否关闭private boolean closed;//根据configuration和事务来初始化构造器protected BaseExecutor(Configuration configuration, Transaction transaction) {this.transaction = transaction;this.deferredLoads = new ConcurrentLinkedQueue<>();this.localCache = new PerpetualCache("LocalCache");this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");this.closed = false;this.configuration = configuration;this.wrapper = this;}//获取事务,如果关闭了则直接抛出异常 执行器已经被关闭@Overridepublic Transaction getTransaction() {if (closed) {throw new ExecutorException("Executor was closed.");}return transaction;}//关闭 是否回滚@Overridepublic void close(boolean forceRollback) {try {try {rollback(forceRollback);} finally {if (transaction != null) {transaction.close();}}} catch (SQLException e) {// Ignore.  There's nothing that can be done at this point.log.warn("Unexpected exception on closing transaction.  Cause: " + e);} finally {transaction = null;deferredLoads = null;localCache = null;localOutputParameterCache = null;closed = true;}}//是否被关闭@Overridepublic boolean isClosed() {return closed;}//更新会话操作@Overridepublic int update(MappedStatement ms, Object parameter) throws SQLException {//错误上下文实例获取会话IDErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());//如果关闭抛出异常if (closed) {throw new ExecutorException("Executor was closed.");}//清除本地缓存clearLocalCache();//更新会话操作return doUpdate(ms, parameter);}//刷新会话操作 不回滚@Overridepublic List<BatchResult> flushStatements() throws SQLException {return flushStatements(false);}//刷新会话操作public List<BatchResult> flushStatements(boolean isRollBack) throws SQLException {if (closed) {throw new ExecutorException("Executor was closed.");}//操作刷新会话return doFlushStatements(isRollBack);}//查询会话@Overridepublic <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {BoundSql boundSql = ms.getBoundSql(parameter);CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);return query(ms, parameter, rowBounds, resultHandler, key, boundSql);}//带缓存查询会话@SuppressWarnings("unchecked")@Overridepublic <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {//错误上下文增加活动记录ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());//是否关闭检查if (closed) {throw new ExecutorException("Executor was closed.");}//查询栈=0并且要求被刷新缓存的会话操作if (queryStack == 0 && ms.isFlushCacheRequired()) {//清除本地缓存clearLocalCache();}//查询栈+1List<E> list;try {queryStack++;//判断结果处理器是否为空,如果为空从本地缓存获取否则赋值空list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;if (list != null) {//有结果处理器则直接处理缓存外来的参数handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);} else {//没有结果处理器则直接从数据库查list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);}} finally {//查询栈-1维护初始0queryStack--;}//如果查询栈=0则延迟加载队列 进行延迟循环加载if (queryStack == 0) {for (DeferredLoad deferredLoad : deferredLoads) {deferredLoad.load();}//延迟队列清空// issue #601deferredLoads.clear();//如果配置的本地缓存范围是会话层if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {//清除本地缓存// issue #482clearLocalCache();}}return list;}//查询游标集@Overridepublic <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {BoundSql boundSql = ms.getBoundSql(parameter);return doQueryCursor(ms, parameter, rowBounds, boundSql);}//延迟加载@Overridepublic void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) {if (closed) {throw new ExecutorException("Executor was closed.");}DeferredLoad deferredLoad = new DeferredLoad(resultObject, property, key, localCache, configuration, targetType);if (deferredLoad.canLoad()) {deferredLoad.load();} else {deferredLoads.add(new DeferredLoad(resultObject, property, key, localCache, configuration, targetType));}}//创建缓存key@Overridepublic CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {if (closed) {throw new ExecutorException("Executor was closed.");}CacheKey cacheKey = new CacheKey();cacheKey.update(ms.getId());cacheKey.update(rowBounds.getOffset());cacheKey.update(rowBounds.getLimit());cacheKey.update(boundSql.getSql());List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();//之前我们看到的类型处理器注册 在type包下的 可以通过会话的配置获取TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();// mimic DefaultParameterHandler logicfor (ParameterMapping parameterMapping : parameterMappings) {if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;//参数映射获取属性String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) {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);}cacheKey.update(value);}}//如果configuration获取环境不为空,则缓存更新环境IDif (configuration.getEnvironment() != null) {// issue #176cacheKey.update(configuration.getEnvironment().getId());}return cacheKey;}//是否被缓存会话@Overridepublic boolean isCached(MappedStatement ms, CacheKey key) {return localCache.getObject(key) != null;}//提交如果有必要的话,清除本地缓存,刷新会话,事务提交@Overridepublic void commit(boolean required) throws SQLException {if (closed) {throw new ExecutorException("Cannot commit, transaction is already closed");}clearLocalCache();flushStatements();if (required) {transaction.commit();}}//回滚,如果有必要回滚事务@Overridepublic void rollback(boolean required) throws SQLException {if (!closed) {try {clearLocalCache();flushStatements(true);} finally {if (required) {transaction.rollback();}}}}//清除本地缓存@Overridepublic void clearLocalCache() {if (!closed) {localCache.clear();localOutputParameterCache.clear();}}//约定子类实现的操作更新接口protected abstract int doUpdate(MappedStatement ms, Object parameter)throws SQLException;//约定子类操作的刷新会话接口protected abstract List<BatchResult> doFlushStatements(boolean isRollback)throws SQLException;//约定子类操作的查询接口protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)throws SQLException;//约定子类操作的查询结果集接口protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)throws SQLException;//关闭会话protected void closeStatement(Statement statement) {if (statement != null) {try {statement.close();} catch (SQLException e) {// ignore}}}/*** 如果数据库操作访问异常,这个方法被调用报事务异常超时*/protected void applyTransactionTimeout(Statement statement) throws SQLException {StatementUtil.applyTransactionTimeout(statement, statement.getQueryTimeout(), transaction.getTimeout());}//处理本地缓存输出参数private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) {if (ms.getStatementType() == StatementType.CALLABLE) {final Object cachedParameter = localOutputParameterCache.getObject(key);if (cachedParameter != null && parameter != null) {final MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter);final MetaObject metaParameter = configuration.newMetaObject(parameter);for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {if (parameterMapping.getMode() != ParameterMode.IN) {final String parameterName = parameterMapping.getProperty();final Object cachedValue = metaCachedParameter.getValue(parameterName);metaParameter.setValue(parameterName, cachedValue);}}}}}//从数据库查询private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {List<E> list;//本地缓存存储localCache.putObject(key, EXECUTION_PLACEHOLDER);try {//执行查询list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);} finally {//本地缓存移除localCache.removeObject(key);}//本地缓存存储新的localCache.putObject(key, list);//如果会话类型是回调,则本地外放参数缓存存放if (ms.getStatementType() == StatementType.CALLABLE) {localOutputParameterCache.putObject(key, parameter);}return list;}//获取事务链接protected Connection getConnection(Log statementLog) throws SQLException {Connection connection = transaction.getConnection();if (statementLog.isDebugEnabled()) {return ConnectionLogger.newInstance(connection, statementLog, queryStack);} else {return connection;}}//设置执行器包装器@Overridepublic void setExecutorWrapper(Executor wrapper) {this.wrapper = wrapper;}//延迟加载类private static class DeferredLoad {//元对象private final MetaObject resultObject;//属性private final String property;//目标类型private final Class<?> targetType;//缓存keyprivate final CacheKey key;//本地缓存private final PerpetualCache localCache;//对象工厂private final ObjectFactory objectFactory;//结果提取器private final ResultExtractor resultExtractor;// issue #781//延迟加载构造器public DeferredLoad(MetaObject resultObject,String property,CacheKey key,PerpetualCache localCache,Configuration configuration,Class<?> targetType) {this.resultObject = resultObject;this.property = property;this.key = key;this.localCache = localCache;this.objectFactory = configuration.getObjectFactory();this.resultExtractor = new ResultExtractor(configuration, objectFactory);this.targetType = targetType;}//是否可以被加载public boolean canLoad() {return localCache.getObject(key) != null && localCache.getObject(key) != EXECUTION_PLACEHOLDER;}//加载public void load() {@SuppressWarnings("unchecked")// we suppose we get back a ListList<Object> list = (List<Object>) localCache.getObject(key);Object value = resultExtractor.extractObjectFromList(list, targetType);resultObject.setValue(property, value);}}}

2.2.7、SimpleExecutor源码分析


public class SimpleExecutor extends BaseExecutor {//构造执行器public SimpleExecutor(Configuration configuration, Transaction transaction) {super(configuration, transaction);}//执行会话操作@Overridepublic 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);}}//执行查询@Overridepublic <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);stmt = prepareStatement(handler, ms.getStatementLog());return handler.query(stmt, resultHandler);} finally {closeStatement(stmt);}}//执行查询游标集@Overrideprotected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {Configuration configuration = ms.getConfiguration();StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);Statement stmt = prepareStatement(handler, ms.getStatementLog());Cursor<E> cursor = handler.queryCursor(stmt);stmt.closeOnCompletion();return cursor;}//刷新会话@Overridepublic List<BatchResult> doFlushStatements(boolean isRollback) {return Collections.emptyList();}//预准备会话private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {Statement stmt;Connection connection = getConnection(statementLog);stmt = handler.prepare(connection, transaction.getTimeout());handler.parameterize(stmt);return stmt;}}

2.2.8、RoutingStatementHandler和PreparedStatementHandler源码分析


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());}}//准备@Overridepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {return delegate.prepare(connection, transactionTimeout);}//参数化@Overridepublic void parameterize(Statement statement) throws SQLException {delegate.parameterize(statement);}//执行@Overridepublic void batch(Statement statement) throws SQLException {delegate.batch(statement);}//更新@Overridepublic int update(Statement statement) throws SQLException {return delegate.update(statement);}//查询@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {return delegate.query(statement, resultHandler);}//查询游标@Overridepublic <E> Cursor<E> queryCursor(Statement statement) throws SQLException {return delegate.queryCursor(statement);}//执行sql@Overridepublic BoundSql getBoundSql() {return delegate.getBoundSql();}//获取参数处理器@Overridepublic ParameterHandler getParameterHandler() {return delegate.getParameterHandler();}
}

public class PreparedStatementHandler extends BaseStatementHandler {//构造函数public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);}//更新@Overridepublic 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;}//批量执行@Overridepublic void batch(Statement statement) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.addBatch();}//查询@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.execute();return resultSetHandler.handleResultSets(ps);}//查询游标集@Overridepublic <E> Cursor<E> queryCursor(Statement statement) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.execute();return resultSetHandler.handleCursorResultSets(ps);}//实例话会话@Overrideprotected 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() == ResultSetType.DEFAULT) {return connection.prepareStatement(sql);} else {return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);}}//参数化会话@Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters((PreparedStatement) statement);}}

2.5、Part4​【结果集处理】⚡️结果集处理封装

2.5.1、DefaultResultSetHandler源码分析


public class DefaultResultSetHandler implements ResultSetHandler {//延迟对象private static final Object DEFERRED = new Object();//执行器private final Executor executor;//全局配置private final Configuration configuration;//映射会话private final MappedStatement mappedStatement;//行数据private final RowBounds rowBounds;//参数处理器private final ParameterHandler parameterHandler;//结果处理器private final ResultHandler<?> resultHandler;//执行SQLprivate final BoundSql boundSql;//类型处理器注册器private final TypeHandlerRegistry typeHandlerRegistry;//对象工厂private final ObjectFactory objectFactory;//反射工厂private final ReflectorFactory reflectorFactory;//嵌套结果映射// nested resultmapsprivate final Map<CacheKey, Object> nestedResultObjects = new HashMap<>();//原型对象private final Map<String, Object> ancestorObjects = new HashMap<>();//先前行值private Object previousRowValue;//多个结果集// multiple resultsetsprivate final Map<String, ResultMapping> nextResultMaps = new HashMap<>();//等待的关系private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<>();//自动映射的缓存// Cached Automappingsprivate final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<>();//暂时标记 使用构造器映射(使用属性减少内存使用)// temporary marking flag that indicate using constructor mapping (use field to reduce memory usage)private boolean useConstructorMappings;//等待关系private static class PendingRelation {public MetaObject metaObject;public ResultMapping propertyMapping;}//未映射的列自动映射  内部类private static class UnMappedColumnAutoMapping {private final String column;private final String property;private final TypeHandler<?> typeHandler;private final boolean primitive;public UnMappedColumnAutoMapping(String column, String property, TypeHandler<?> typeHandler, boolean primitive) {this.column = column;this.property = property;this.typeHandler = typeHandler;this.primitive = primitive;}}//有参构造函数public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql,RowBounds rowBounds) {this.executor = executor;this.configuration = mappedStatement.getConfiguration();this.mappedStatement = mappedStatement;this.rowBounds = rowBounds;this.parameterHandler = parameterHandler;this.boundSql = boundSql;this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();this.objectFactory = configuration.getObjectFactory();this.reflectorFactory = configuration.getReflectorFactory();this.resultHandler = resultHandler;}//处理输出参数// HANDLE OUTPUT PARAMETER//@Overridepublic void handleOutputParameters(CallableStatement cs) throws SQLException {final Object parameterObject = parameterHandler.getParameterObject();final MetaObject metaParam = configuration.newMetaObject(parameterObject);final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();for (int i = 0; i < parameterMappings.size(); i++) {final ParameterMapping parameterMapping = parameterMappings.get(i);if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {if (ResultSet.class.equals(parameterMapping.getJavaType())) {handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);} else {final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));}}}}//处理游标输出参数private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam) throws SQLException {if (rs == null) {return;}try {final String resultMapId = parameterMapping.getResultMapId();final ResultMap resultMap = configuration.getResultMap(resultMapId);final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);if (this.resultHandler == null) {final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());} else {handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);}} finally {// issue #228 (close resultsets)closeResultSet(rs);}}//处理结果集// HANDLE RESULT SETS//@Overridepublic List<Object> handleResultSets(Statement stmt) throws SQLException {ErrorContext.instance().activity("handling results").object(mappedStatement.getId());final List<Object> multipleResults = new ArrayList<>();int resultSetCount = 0;ResultSetWrapper rsw = getFirstResultSet(stmt);List<ResultMap> resultMaps = mappedStatement.getResultMaps();int resultMapCount = resultMaps.size();validateResultMapsCount(rsw, resultMapCount);while (rsw != null && resultMapCount > resultSetCount) {ResultMap resultMap = resultMaps.get(resultSetCount);handleResultSet(rsw, resultMap, multipleResults, null);rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}String[] resultSets = mappedStatement.getResultSets();if (resultSets != null) {while (rsw != null && resultSetCount < resultSets.length) {ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);if (parentMapping != null) {String nestedResultMapId = parentMapping.getNestedResultMapId();ResultMap resultMap = configuration.getResultMap(nestedResultMapId);handleResultSet(rsw, resultMap, null, parentMapping);}rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}}return collapseSingleResultList(multipleResults);}//处理游标结果集@Overridepublic <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {ErrorContext.instance().activity("handling cursor results").object(mappedStatement.getId());ResultSetWrapper rsw = getFirstResultSet(stmt);List<ResultMap> resultMaps = mappedStatement.getResultMaps();int resultMapCount = resultMaps.size();validateResultMapsCount(rsw, resultMapCount);if (resultMapCount != 1) {throw new ExecutorException("Cursor results cannot be mapped to multiple resultMaps");}ResultMap resultMap = resultMaps.get(0);return new DefaultCursor<>(this, resultMap, rsw, rowBounds);}//获取首个结果集private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {ResultSet rs = stmt.getResultSet();while (rs == null) {// move forward to get the first resultset in case the driver// doesn't return the resultset as the first result (HSQLDB 2.1)if (stmt.getMoreResults()) {rs = stmt.getResultSet();} else {if (stmt.getUpdateCount() == -1) {// no more results. Must be no resultsetbreak;}}}return rs != null ? new ResultSetWrapper(rs, configuration) : null;}//获取下一个结果集private ResultSetWrapper getNextResultSet(Statement stmt) {// Making this method tolerant of bad JDBC driverstry {if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {// Crazy Standard JDBC way of determining if there are more resultsif (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {ResultSet rs = stmt.getResultSet();if (rs == null) {return getNextResultSet(stmt);} else {return new ResultSetWrapper(rs, configuration);}}}} catch (Exception e) {// Intentionally ignored.}return null;}//关闭结果集private void closeResultSet(ResultSet rs) {try {if (rs != null) {rs.close();}} catch (SQLException e) {// ignore}}//嵌套结果对象清空private void cleanUpAfterHandlingResultSet() {nestedResultObjects.clear();}//校验结果映射数量private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) {if (rsw != null && resultMapCount < 1) {throw new ExecutorException("A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId()+ "'.  It's likely that neither a Result Type nor a Result Map was specified.");}}//处理结果集private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {try {if (parentMapping != null) {handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);} else {if (resultHandler == null) {DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);multipleResults.add(defaultResultHandler.getResultList());} else {handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);}}} finally {// issue #228 (close resultsets)closeResultSet(rsw.getResultSet());}}////处理单个结果集@SuppressWarnings("unchecked")private List<Object> collapseSingleResultList(List<Object> multipleResults) {return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;}// 简单的结果集 处理行数据// HANDLE ROWS FOR SIMPLE RESULTMAP//public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {if (resultMap.hasNestedResultMaps()) {ensureNoRowBounds();checkResultHandler();handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);} else {handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);}}//确保没行数据private void ensureNoRowBounds() {if (configuration.isSafeRowBoundsEnabled() && rowBounds != null && (rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT || rowBounds.getOffset() > RowBounds.NO_ROW_OFFSET)) {throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. "+ "Use safeRowBoundsEnabled=false setting to bypass this check.");}}//检查结果处理器protected void checkResultHandler() {if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.isResultOrdered()) {throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely used with a custom ResultHandler. "+ "Use safeResultHandlerEnabled=false setting to bypass this check "+ "or ensure your statement returns ordered data and set resultOrdered=true on it.");}}//处理简单结果集的行数据值private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {DefaultResultContext<Object> resultContext = new DefaultResultContext<>();ResultSet resultSet = rsw.getResultSet();skipRows(resultSet, rowBounds);while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);Object rowValue = getRowValue(rsw, discriminatedResultMap, null);storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);}}//存储对象private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {if (parentMapping != null) {linkToParents(rs, parentMapping, rowValue);} else {callResultHandler(resultHandler, resultContext, rowValue);}}//调用结果处理器@SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object>*/)private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {resultContext.nextResultObject(rowValue);((ResultHandler<Object>) resultHandler).handleResult(resultContext);}//应该执行更多行private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) {return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();}//跳过行数据private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {rs.absolute(rowBounds.getOffset());}} else {for (int i = 0; i < rowBounds.getOffset(); i++) {if (!rs.next()) {break;}}}}// 获取简单结果集的行数据值// GET VALUE FROM ROW FOR SIMPLE RESULT MAP//private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {final ResultLoaderMap lazyLoader = new ResultLoaderMap();Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);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, columnPrefix) || foundValues;}foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;foundValues = lazyLoader.size() > 0 || foundValues;rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;}return rowValue;}//应该自动映射private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {if (resultMap.getAutoMapping() != null) {return resultMap.getAutoMapping();} else {if (isNested) {return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();} else {return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();}}}// 属性映射// PROPERTY MAPPINGS//private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);boolean foundValues = false;final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();for (ResultMapping propertyMapping : propertyMappings) {String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);if (propertyMapping.getNestedResultMapId() != null) {// the user added a column attribute to a nested result map, ignore itcolumn = null;}if (propertyMapping.isCompositeResult()|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))|| propertyMapping.getResultSet() != null) {Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);// issue #541 make property optionalfinal String property = propertyMapping.getProperty();if (property == null) {continue;} else if (value == DEFERRED) {foundValues = true;continue;}if (value != null) {foundValues = true;}if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {// gcode issue #377, call setter on nulls (value is not 'found')metaObject.setValue(property, value);}}}return foundValues;}// 获取属性映射的值private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {if (propertyMapping.getNestedQueryId() != null) {return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);} else if (propertyMapping.getResultSet() != null) {addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?return DEFERRED;} else {final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);return typeHandler.getResult(rs, column);}}// 创建自动映射private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {final String mapKey = resultMap.getId() + ":" + columnPrefix;List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);if (autoMapping == null) {autoMapping = new ArrayList<>();final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);for (String columnName : unmappedColumnNames) {String propertyName = columnName;if (columnPrefix != null && !columnPrefix.isEmpty()) {// When columnPrefix is specified,// ignore columns without the prefix.if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {propertyName = columnName.substring(columnPrefix.length());} else {continue;}}final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());if (property != null && metaObject.hasSetter(property)) {if (resultMap.getMappedProperties().contains(property)) {continue;}final Class<?> propertyType = metaObject.getSetterType(property);if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));} else {configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName, property, propertyType);}} else {configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);}}autoMappingsCache.put(mapKey, autoMapping);}return autoMapping;}//是否应用自动映射private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);boolean foundValues = false;if (!autoMapping.isEmpty()) {for (UnMappedColumnAutoMapping mapping : autoMapping) {final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);if (value != null) {foundValues = true;}if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {// gcode issue #377, call setter on nulls (value is not 'found')metaObject.setValue(mapping.property, value);}}}return foundValues;}//多个结果集// MULTIPLE RESULT SETSprivate void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn());List<PendingRelation> parents = pendingRelations.get(parentKey);if (parents != null) {for (PendingRelation parent : parents) {if (parent != null && rowValue != null) {linkObjects(parent.metaObject, parent.propertyMapping, rowValue);}}}}//添加等待子关系private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping) throws SQLException {CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getColumn());PendingRelation deferLoad = new PendingRelation();deferLoad.metaObject = metaResultObject;deferLoad.propertyMapping = parentMapping;List<PendingRelation> relations = pendingRelations.computeIfAbsent(cacheKey, k -> new ArrayList<>());// issue #255relations.add(deferLoad);ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());if (previous == null) {nextResultMaps.put(parentMapping.getResultSet(), parentMapping);} else {if (!previous.equals(parentMapping)) {throw new ExecutorException("Two different properties are mapped to the same resultSet");}}}//创建多个结果集的keyprivate CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns) throws SQLException {CacheKey cacheKey = new CacheKey();cacheKey.update(resultMapping);if (columns != null && names != null) {String[] columnsArray = columns.split(",");String[] namesArray = names.split(",");for (int i = 0; i < columnsArray.length; i++) {Object value = rs.getString(columnsArray[i]);if (value != null) {cacheKey.update(namesArray[i]);cacheKey.update(value);}}}return cacheKey;}//  创建结果集// INSTANTIATION & CONSTRUCTOR MAPPING//private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {this.useConstructorMappings = false; // reset previous mapping resultfinal List<Class<?>> constructorArgTypes = new ArrayList<>();final List<Object> constructorArgs = new ArrayList<>();Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();for (ResultMapping propertyMapping : propertyMappings) {// issue gcode #109 && issue #149if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);break;}}}this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping resultreturn resultObject;}//创建结果对象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);}throw new ExecutorException("Do not know how to create an instance of " + resultType);}//创建参数化的结果对象Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings,List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) {boolean foundValues = false;for (ResultMapping constructorMapping : constructorMappings) {final Class<?> parameterType = constructorMapping.getJavaType();final String column = constructorMapping.getColumn();final Object value;try {if (constructorMapping.getNestedQueryId() != null) {value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);} else if (constructorMapping.getNestedResultMapId() != null) {final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());value = getRowValue(rsw, resultMap, getColumnPrefix(columnPrefix, constructorMapping));} else {final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));}} catch (ResultMapException | SQLException e) {throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);}constructorArgTypes.add(parameterType);constructorArgs.add(value);foundValues = value != null || foundValues;}return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;}//创建根据构造特征的对象private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) throws SQLException {final Constructor<?>[] constructors = resultType.getDeclaredConstructors();final Constructor<?> defaultConstructor = findDefaultConstructor(constructors);if (defaultConstructor != null) {return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, defaultConstructor);} else {for (Constructor<?> constructor : constructors) {if (allowedConstructorUsingTypeHandlers(constructor, rsw.getJdbcTypes())) {return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, constructor);}}}throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());}//使用构造器创建对象private Object createUsingConstructor(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor) throws SQLException {boolean foundValues = false;for (int i = 0; i < constructor.getParameterTypes().length; i++) {Class<?> parameterType = constructor.getParameterTypes()[i];String columnName = rsw.getColumnNames().get(i);TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);Object value = typeHandler.getResult(rsw.getResultSet(), columnName);constructorArgTypes.add(parameterType);constructorArgs.add(value);foundValues = value != null || foundValues;}return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;}//找到默认的构造器private Constructor<?> findDefaultConstructor(final Constructor<?>[] constructors) {if (constructors.length == 1) {return constructors[0];}for (final Constructor<?> constructor : constructors) {if (constructor.isAnnotationPresent(AutomapConstructor.class)) {return constructor;}}return null;}//允许使用类型处理器的构造器private boolean allowedConstructorUsingTypeHandlers(final Constructor<?> constructor, final List<JdbcType> jdbcTypes) {final Class<?>[] parameterTypes = constructor.getParameterTypes();if (parameterTypes.length != jdbcTypes.size()) {return false;}for (int i = 0; i < parameterTypes.length; i++) {if (!typeHandlerRegistry.hasTypeHandler(parameterTypes[i], jdbcTypes.get(i))) {return false;}}return true;}//创建主要的结果对象private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {final Class<?> resultType = resultMap.getType();final String columnName;if (!resultMap.getResultMappings().isEmpty()) {final List<ResultMapping> resultMappingList = resultMap.getResultMappings();final ResultMapping mapping = resultMappingList.get(0);columnName = prependPrefix(mapping.getColumn(), columnPrefix);} else {columnName = rsw.getColumnNames().get(0);}final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);return typeHandler.getResult(rsw.getResultSet(), columnName);}//  嵌套查询// NESTED QUERY//private Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix) throws SQLException {final String nestedQueryId = constructorMapping.getNestedQueryId();final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping, nestedQueryParameterType, columnPrefix);Object value = null;if (nestedQueryParameterObject != null) {final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);final Class<?> targetType = constructorMapping.getJavaType();final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);value = resultLoader.loadResult();}return value;}// 获取嵌套查询映射值private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {final String nestedQueryId = propertyMapping.getNestedQueryId();final String property = propertyMapping.getProperty();final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix);Object value = null;if (nestedQueryParameterObject != null) {final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);final Class<?> targetType = propertyMapping.getJavaType();if (executor.isCached(nestedQuery, key)) {executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);value = DEFERRED;} else {final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);if (propertyMapping.isLazy()) {lazyLoader.addLoader(property, metaResultObject, resultLoader);value = DEFERRED;} else {value = resultLoader.loadResult();}}}return value;}//准备参数 为嵌套查询private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {if (resultMapping.isCompositeResult()) {return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);} else {return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);}}//准备单个key参数private Object prepareSimpleKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {final TypeHandler<?> typeHandler;if (typeHandlerRegistry.hasTypeHandler(parameterType)) {typeHandler = typeHandlerRegistry.getTypeHandler(parameterType);} else {typeHandler = typeHandlerRegistry.getUnknownTypeHandler();}return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));}//准备混合key参数private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {final Object parameterObject = instantiateParameterObject(parameterType);final MetaObject metaObject = configuration.newMetaObject(parameterObject);boolean foundValues = false;for (ResultMapping innerResultMapping : resultMapping.getComposites()) {final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);final Object propValue = typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix));// issue #353 & #560 do not execute nested query if key is nullif (propValue != null) {metaObject.setValue(innerResultMapping.getProperty(), propValue);foundValues = true;}}return foundValues ? parameterObject : null;}//实例话参数对象private Object instantiateParameterObject(Class<?> parameterType) {if (parameterType == null) {return new HashMap<>();} else if (ParamMap.class.equals(parameterType)) {return new HashMap<>(); // issue #649} else {return objectFactory.create(parameterType);}}//解决区别结果集// DISCRIMINATOR//public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {Set<String> pastDiscriminators = new HashSet<>();Discriminator discriminator = resultMap.getDiscriminator();while (discriminator != null) {final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));if (configuration.hasResultMap(discriminatedMapId)) {resultMap = configuration.getResultMap(discriminatedMapId);Discriminator lastDiscriminator = discriminator;discriminator = resultMap.getDiscriminator();if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {break;}} else {break;}}return resultMap;}//获取区别值private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException {final ResultMapping resultMapping = discriminator.getResultMapping();final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));}//封装前缀private String prependPrefix(String columnName, String prefix) {if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {return columnName;}return prefix + columnName;}//  处理嵌套结果映射// HANDLE NESTED RESULT MAPS//private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {final DefaultResultContext<Object> resultContext = new DefaultResultContext<>();ResultSet resultSet = rsw.getResultSet();skipRows(resultSet, rowBounds);Object rowValue = previousRowValue;while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);Object partialObject = nestedResultObjects.get(rowKey);// issue #577 && #542if (mappedStatement.isResultOrdered()) {if (partialObject == null && rowValue != null) {nestedResultObjects.clear();storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);}rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);} else {rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);if (partialObject == null) {storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);}}}if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);previousRowValue = null;} else if (rowValue != null) {previousRowValue = rowValue;}}//  从嵌套结果映射中获取值// GET VALUE FROM ROW FOR NESTED RESULT MAP//private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException {final String resultMapId = resultMap.getId();Object rowValue = partialObject;if (rowValue != null) {final MetaObject metaObject = configuration.newMetaObject(rowValue);putAncestor(rowValue, resultMapId);applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);ancestorObjects.remove(resultMapId);} else {final ResultLoaderMap lazyLoader = new ResultLoaderMap();rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {final MetaObject metaObject = configuration.newMetaObject(rowValue);boolean foundValues = this.useConstructorMappings;if (shouldApplyAutomaticMappings(resultMap, true)) {foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;}foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;putAncestor(rowValue, resultMapId);foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;ancestorObjects.remove(resultMapId);foundValues = lazyLoader.size() > 0 || foundValues;rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;}if (combinedKey != CacheKey.NULL_CACHE_KEY) {nestedResultObjects.put(combinedKey, rowValue);}}return rowValue;}private void putAncestor(Object resultObject, String resultMapId) {ancestorObjects.put(resultMapId, resultObject);}//  嵌套结果集// NESTED RESULT MAP (JOIN MAPPING)//private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {boolean foundValues = false;for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {final String nestedResultMapId = resultMapping.getNestedResultMapId();if (nestedResultMapId != null && resultMapping.getResultSet() == null) {try {final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);if (resultMapping.getColumnPrefix() == null) {// try to fill circular reference only when columnPrefix// is not specified for the nested result map (issue #215)Object ancestorObject = ancestorObjects.get(nestedResultMapId);if (ancestorObject != null) {if (newObject) {linkObjects(metaObject, resultMapping, ancestorObject); // issue #385}continue;}}final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);Object rowValue = nestedResultObjects.get(combinedKey);boolean knownValue = rowValue != null;instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatoryif (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) {rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue);if (rowValue != null && !knownValue) {linkObjects(metaObject, resultMapping, rowValue);foundValues = true;}}} catch (SQLException e) {throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);}}}return foundValues;}//获取列前缀private String getColumnPrefix(String parentPrefix, ResultMapping resultMapping) {final StringBuilder columnPrefixBuilder = new StringBuilder();if (parentPrefix != null) {columnPrefixBuilder.append(parentPrefix);}if (resultMapping.getColumnPrefix() != null) {columnPrefixBuilder.append(resultMapping.getColumnPrefix());}return columnPrefixBuilder.length() == 0 ? null : columnPrefixBuilder.toString().toUpperCase(Locale.ENGLISH);}//应用非空字段是否有值private boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSetWrapper rsw) throws SQLException {Set<String> notNullColumns = resultMapping.getNotNullColumns();if (notNullColumns != null && !notNullColumns.isEmpty()) {ResultSet rs = rsw.getResultSet();for (String column : notNullColumns) {rs.getObject(prependPrefix(column, columnPrefix));if (!rs.wasNull()) {return true;}}return false;} else if (columnPrefix != null) {for (String columnName : rsw.getColumnNames()) {if (columnName.toUpperCase().startsWith(columnPrefix.toUpperCase())) {return true;}}return false;}return true;}//获取嵌套结果映射private ResultMap getNestedResultMap(ResultSet rs, String nestedResultMapId, String columnPrefix) throws SQLException {ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId);return resolveDiscriminatedResultMap(rs, nestedResultMap, columnPrefix);}//  唯一的结果key// UNIQUE RESULT KEY//private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {final CacheKey cacheKey = new CacheKey();cacheKey.update(resultMap.getId());List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);if (resultMappings.isEmpty()) {if (Map.class.isAssignableFrom(resultMap.getType())) {createRowKeyForMap(rsw, cacheKey);} else {createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);}} else {createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);}if (cacheKey.getUpdateCount() < 2) {return CacheKey.NULL_CACHE_KEY;}return cacheKey;}//合起来keyprivate CacheKey combineKeys(CacheKey rowKey, CacheKey parentRowKey) {if (rowKey.getUpdateCount() > 1 && parentRowKey.getUpdateCount() > 1) {CacheKey combinedKey;try {combinedKey = rowKey.clone();} catch (CloneNotSupportedException e) {throw new ExecutorException("Error cloning cache key.  Cause: " + e, e);}combinedKey.update(parentRowKey);return combinedKey;}return CacheKey.NULL_CACHE_KEY;}//获取行key的结果映射private List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) {List<ResultMapping> resultMappings = resultMap.getIdResultMappings();if (resultMappings.isEmpty()) {resultMappings = resultMap.getPropertyResultMappings();}return resultMappings;}//创建行key对于映射的属性private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, List<ResultMapping> resultMappings, String columnPrefix) throws SQLException {for (ResultMapping resultMapping : resultMappings) {if (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null) {// Issue #392final ResultMap nestedResultMap = configuration.getResultMap(resultMapping.getNestedResultMapId());createRowKeyForMappedProperties(nestedResultMap, rsw, cacheKey, nestedResultMap.getConstructorResultMappings(),prependPrefix(resultMapping.getColumnPrefix(), columnPrefix));} else if (resultMapping.getNestedQueryId() == null) {final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);final TypeHandler<?> th = resultMapping.getTypeHandler();List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);// Issue #114if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {final Object value = th.getResult(rsw.getResultSet(), column);if (value != null || configuration.isReturnInstanceForEmptyRow()) {cacheKey.update(column);cacheKey.update(value);}}}}}//创建行key对应未映射的属性private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, String columnPrefix) throws SQLException {final MetaClass metaType = MetaClass.forClass(resultMap.getType(), reflectorFactory);List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);for (String column : unmappedColumnNames) {String property = column;if (columnPrefix != null && !columnPrefix.isEmpty()) {// When columnPrefix is specified, ignore columns without the prefix.if (column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {property = column.substring(columnPrefix.length());} else {continue;}}if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {String value = rsw.getResultSet().getString(column);if (value != null) {cacheKey.update(column);cacheKey.update(value);}}}}//创建行keyprivate void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException {List<String> columnNames = rsw.getColumnNames();for (String columnName : columnNames) {final String value = rsw.getResultSet().getString(columnName);if (value != null) {cacheKey.update(columnName);cacheKey.update(value);}}}//链接对象private void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue) {final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);if (collectionProperty != null) {final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);targetMetaObject.add(rowValue);} else {metaObject.setValue(resultMapping.getProperty(), rowValue);}}//实例话集合属性如果合适的private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {final String propertyName = resultMapping.getProperty();Object propertyValue = metaObject.getValue(propertyName);if (propertyValue == null) {Class<?> type = resultMapping.getJavaType();if (type == null) {type = metaObject.getSetterType(propertyName);}try {if (objectFactory.isCollection(type)) {propertyValue = objectFactory.create(type);metaObject.setValue(propertyName, propertyValue);return propertyValue;}} catch (Exception e) {throw new ExecutorException("Error instantiating collection property for result '" + resultMapping.getProperty() + "'.  Cause: " + e, e);}} else if (objectFactory.isCollection(propertyValue.getClass())) {return propertyValue;}return null;}//结果对象的类型处理器是否存在private boolean hasTypeHandlerForResultObject(ResultSetWrapper rsw, Class<?> resultType) {if (rsw.getColumnNames().size() == 1) {return typeHandlerRegistry.hasTypeHandler(resultType, rsw.getJdbcType(rsw.getColumnNames().get(0)));}return typeHandlerRegistry.hasTypeHandler(resultType);}}

2.5.2、Jdbc3KeyGenerator源码分析


/*** jdbc链接主键生成* @author Clinton Begin* @author Kazuki Shimizu*/
public class Jdbc3KeyGenerator implements KeyGenerator {//参数名字private static final String SECOND_GENERIC_PARAM_NAME = ParamNameResolver.GENERIC_NAME_PREFIX + "2";/*** 3.4.3版本以后 一个共享的实例* A shared instance.** @since 3.4.3*/public static final Jdbc3KeyGenerator INSTANCE = new Jdbc3KeyGenerator();//生成太多key的错误提示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.";//在执行器前执行,什么也不做@Overridepublic void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {// do nothing}//在执行器后执行,执行会话@Overridepublic void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {processBatch(ms, stmt, parameter);}//执行public void processBatch(MappedStatement ms, Statement stmt, Object parameter) {//映射会话获取key属性final String[] keyProperties = ms.getKeyProperties();if (keyProperties == null || keyProperties.length == 0) {return;}//会话获取主键try (ResultSet rs = stmt.getGeneratedKeys()) {//结果集获取元数据final ResultSetMetaData rsmd = rs.getMetaData();//获取全局配置final Configuration configuration = ms.getConfiguration();if (rsmd.getColumnCount() < keyProperties.length) {// Error?} else {//分配key主键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);}}//分配key主键@SuppressWarnings("unchecked")private void assignKeys(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd, String[] keyProperties,Object parameter) throws SQLException {//使用@Param多个参数或者单个参数if (parameter instanceof ParamMap || parameter instanceof StrictMap) {// Multi-param or single param with @ParamassignKeysToParamMap(configuration, rs, rsmd, keyProperties, (Map<String, ?>) parameter);} else if (parameter instanceof ArrayList && !((ArrayList<?>) parameter).isEmpty()&& ((ArrayList<?>) parameter).get(0) instanceof ParamMap) {//批量操作 @Param多个参数或者单个参数// Multi-param or single param with @Param in batch operationassignKeysToParamMapList(configuration, rs, rsmd, keyProperties, ((ArrayList<ParamMap<?>>) parameter));} else {//没有@Param的单个参数// Single param without @ParamassignKeysToParam(configuration, rs, rsmd, keyProperties, parameter);}}//分配主键给参数private void assignKeysToParam(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,String[] keyProperties, Object parameter) throws SQLException {//集合化参数Collection<?> params = collectionize(parameter);if (params.isEmpty()) {return;}//分配集合List<KeyAssigner> 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()) {if (!iterator.hasNext()) {throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, params.size()));}//给每个会话绑定Object param = iterator.next();assignerList.forEach(x -> x.assign(rs, param));}}//分配主键给参数map集合private void assignKeysToParamMapList(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,String[] keyProperties, ArrayList<ParamMap<?>> paramMapList) throws SQLException {Iterator<ParamMap<?>> iterator = paramMapList.iterator();List<KeyAssigner> assignerList = new ArrayList<>();long counter = 0;//遍历结果信息while (rs.next()) {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++) {assignerList.add(getAssignerForParamMap(configuration, rsmd, i + 1, paramMap, keyProperties[i], keyProperties, false).getValue());}}assignerList.forEach(x -> x.assign(rs, paramMap));counter++;}}//分配主键给参数Mapprivate void assignKeysToParamMap(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,String[] keyProperties, Map<String, ?> paramMap) throws SQLException {if (paramMap.isEmpty()) {return;}//遍历map的key属性Map<String, Entry<Iterator<?>, List<KeyAssigner>>> assignerMap = new HashMap<>();for (int i = 0; i < keyProperties.length; i++) {Entry<String, KeyAssigner> entry = getAssignerForParamMap(configuration, rsmd, i + 1, paramMap, keyProperties[i],keyProperties, true);Entry<Iterator<?>, List<KeyAssigner>> iteratorPair = assignerMap.computeIfAbsent(entry.getKey(),k -> entry(collectionize(paramMap.get(k)).iterator(), new ArrayList<>()));iteratorPair.getValue().add(entry.getValue());}//遍历返回结果赋值long counter = 0;while (rs.next()) {for (Entry<Iterator<?>, List<KeyAssigner>> pair : assignerMap.values()) {if (!pair.getKey().hasNext()) {throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, counter));}Object param = pair.getKey().next();pair.getValue().forEach(x -> x.assign(rs, param));}counter++;}}//从参数Map获取分配private Entry<String, KeyAssigner> getAssignerForParamMap(Configuration config, ResultSetMetaData rsmd,int columnPosition, Map<String, ?> paramMap, String keyProperty, String[] keyProperties, boolean omitParamName) {Set<String> keySet = paramMap.keySet();//如果唯一的参数这种方式使用{@code @Param("param2")},一定是被param2.x这样引用// A caveat : if the only parameter has {@code @Param("param2")} on it,// it must be referenced with param name e.g. 'param2.x'.//主键集合不包括参数名字boolean singleParam = !keySet.contains(SECOND_GENERIC_PARAM_NAME);//属性获取第一个点int firstDot = keyProperty.indexOf('.');//如果是没有if (firstDot == -1) {//如果是单个参数,直接分配if (singleParam) {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 "+ keySet);}//从0到第一个点截断,取后面的参数名字String paramName = keyProperty.substring(0, firstDot);//判断key集合是否包含参数名字if (keySet.contains(paramName)) {String argParamName = omitParamName ? null : paramName;String argKeyProperty = keyProperty.substring(firstDot + 1);return entry(paramName, new KeyAssigner(config, rsmd, columnPosition, argParamName, argKeyProperty));} else if (singleParam) {//单个参数的分配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 "+ keySet);}}//从单个参数获取分配private Entry<String, KeyAssigner> getAssignerForSingleParam(Configuration config, ResultSetMetaData rsmd,int columnPosition, Map<String, ?> paramMap, String keyProperty, boolean omitParamName) {// Assume 'keyProperty' to be a property of the single param.//假设这个属性的参数有'keyProperty'String singleParamName = nameOfSingleParam(paramMap);String argParamName = omitParamName ? null : singleParamName;//封装该实体类return entry(singleParamName, new KeyAssigner(config, rsmd, columnPosition, argParamName, keyProperty));}//单个参数的名字private static String nameOfSingleParam(Map<String, ?> paramMap) {// There is virtually one parameter, so any key works.return paramMap.keySet().iterator().next();}//集合化参数private static Collection<?> collectionize(Object param) {if (param instanceof Collection) {return (Collection<?>) param;} else if (param instanceof Object[]) {return Arrays.asList((Object[]) param);} else {return Arrays.asList(param);}}//在Java9中取代了Map.entry(key, value)的方式private static <K, V> Entry<K, V> entry(K key, V value) {// Replace this with Map.entry(key, value) in Java 9.return new AbstractMap.SimpleImmutableEntry<>(key, value);}//主键分配类private class KeyAssigner {//全局配置private final Configuration configuration;//结果元数据集private final ResultSetMetaData rsmd;//类型处理注册器private final TypeHandlerRegistry typeHandlerRegistry;//列位置private final int columnPosition;//参数名字private final String paramName;//属性名字private final String propertyName;//类型处理器private TypeHandler<?> typeHandler;//构造函数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;}//分配结果集和参数protected void assign(ResultSet rs, Object param) {if (paramName != null) {// If paramName is set, param is ParamMapparam = ((ParamMap<?>) param).get(paramName);}//获取元对象MetaObject metaParam = configuration.newMetaObject(param);try {//如果类型处理器为空if (typeHandler == null) {//元参数判断是否有set方法if (metaParam.hasSetter(propertyName)) {//元参数获取set类型Class<?> propertyType = metaParam.getSetterType(propertyName);//类型处理器注册器获取对应的类型处理器typeHandler = typeHandlerRegistry.getTypeHandler(propertyType,JdbcType.forCode(rsmd.getColumnType(columnPosition)));} else {throw new ExecutorException("No setter found for the keyProperty '" + propertyName + "' in '"+ metaParam.getOriginalObject().getClass().getName() + "'.");}}if (typeHandler == null) {// Error?} else {//类型处理器处理结果返回值赋值给属性Object value = typeHandler.getResult(rs, columnPosition);metaParam.setValue(propertyName, value);}} catch (SQLException e) {throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e,e);}}}
}

【源码篇】聊聊源码mybatis(更新分析)相关推荐

  1. spring-boot-2.0.3不一样系列之源码篇 - springboot源码一,绝对有值得你看的地方

    前言 上篇:spring-boot-2.0.3不一样系列之shiro - 搭建篇,实现了spring-boot与shiro的整合,效果大家也看到了,工程确实集成了shiro的认证与授权功能.如果大家能 ...

  2. 【源码篇】源码阅读集合

    怎么读达到什么目的 Spring源码 Redis源码 JDK源码 集合源码

  3. 深入浅出Mybatis系列(四)---配置详解之typeAliases别名(mybatis源码篇)

    上篇文章<深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)> 介绍了properties与environments, ...

  4. phpcmsV9 完整更新ckeditor编辑器到最新版 - 源码篇

    phpcmsV9 默认编辑器是ckeditor,但是版本低,使用效果低. 本文 重点解决问题: 更新ckeditor默认编辑器到最新版. phpcms当前版本 : V9.6.3 . 现在将我更换编辑器 ...

  5. 手撸Spring系列12:MyBatis(源码篇)

    说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...

  6. 微信小程序开发导航:精品教程+网友观点+demo源码(5月9日更新)

    1:官方工具:https://mp.weixin.qq.com/debug/w ... tml?t=1476434678461 2:简易教程:https://mp.weixin.qq.com/debu ...

  7. 涨薪秘籍之源码篇:Spring全家桶源码解读,大师晋级笔记

    最近很多人留言说今年找工作太难了,要涨薪几乎更难了 !真的就这么悲观吗?其实不然,我们企业一直都在大量的招人,一直都没停过.只是一点和之前不一样要求变高了,优秀的人一直都缺. 我身边朋友所在的大厂也一 ...

  8. 使用Mahout搭建推荐系统之入门篇3-Mahout源码初探

    2019独角兽企业重金招聘Python工程师标准>>> 用意: 希望了解Mahout中数据的存储方式, 它如何避免java object带来的冗余开销.学完知识,要进行些实战 去分析 ...

  9. Android Jetpack架构组件之 Room(使用、源码篇)

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发 ...

  10. create-react-app教程-源码篇

    原文链接:create-react-app教程-源码篇 之前介绍了create-react-app的基本使用, 为了便于理解一个脚手架脚本是如何运作的,现在来看一下 create-react-app ...

最新文章

  1. 广州企业“掘金”物联网蓝海
  2. Android JNI(三)——JNI数据结构之JNINativeMethod
  3. cuSPARSE库:(二)静态库的支持
  4. 锦州师专高等专科学校计算机,《数据库原理与应用锦州师范高等专科学校计算机系》.ppt...
  5. 自动控制原理5.1---频率特性
  6. oracle常用查询语句
  7. CMMI体系建设的目的和意义
  8. 2021年危险化学品经营单位主要负责人考试及危险化学品经营单位主要负责人找解析
  9. 量化交易——羊驼交易法则
  10. 骑士CMS模版注入+文件包含getshell复现
  11. RISC-V Assembly Programmer's Manual
  12. POJ 1915(双向广搜)
  13. 干货!基于神经网络的多粒度图表征学习
  14. 一百多篇热门经典计算文章 来自 11 个热门的技术类微信公众
  15. 布尔教育2016最新php教程 PHP基础班+PHP大师班视频教程
  16. 智能家居项目开发(一):简单工厂设计模式引入
  17. [转]90后准程序员写给前辈们的一封…
  18. Faststone Capture怎么打开视频编辑器
  19. linux-鸟哥私房菜,基础命令全掌握
  20. 让 new bing 使用 GPT-4 编写一个令人满意的程序全过程赏析

热门文章

  1. 【实验3 循环结构】7-14 循环结构 —— 中国古代著名算题。趣味题目:物不知其数。
  2. 一例所有文件都打不开故障的数据恢复过程(转)
  3. buck电路闭环pi控制matlab图,BUCK电路闭环控制系统的MATLAB仿真
  4. 区块链价值是什么仅仅只是传递吗
  5. 超级计算机模拟现实,超级计算机模拟出了地球磁场真实的模样
  6. HTML5的特效制作的基础介绍
  7. Oracle grant all privileges to user
  8. dolphinscheduler_sql_调用时间参数
  9. React-概叙-JSX
  10. 缓存算法:LFU和LRU的JAVA实现