// 结果集处理器
public interface ResultSetHandler {
// 处理单个或多个多结果集
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
// 处理游标结果集
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
// 处理存储过程的输出参数
void handleOutputParameters(CallableStatement cs) throws SQLException;
// 默认的结果集处理器实现
public class DefaultResultSetHandler implements ResultSetHandler {
// 延迟加载的固定标识值,如果返回该值,就表示需要延迟加载
public static Object DEFERRED = new Object();
// 执行器
public Executor executor;
// 配置信息
public Configuration configuration;
// 映射语句信息
public MappedStatement mappedStatement;
// 分页条件
public RowBounds rowBounds;
// 参数处理器
public ParameterHandler parameterHandler;
// 结果处理器,可以处理每一行记录
public ResultHandler<?> resultHandler;
// SQL的绑定信息
public BoundSql boundSql;
// 类型转换器注册表
public TypeHandlerRegistry typeHandlerRegistry;
// 对象工厂
public ObjectFactory objectFactory;
// 反射工厂
public ReflectorFactory reflectorFactory;
// 嵌套的ResultMap的对象的缓存,所有嵌套属性的缓存对象
public Map<CacheKey, Object> nestedResultObjects = new HashMap<>();
/**
* 嵌套ResultMap的父对象缓存,主要用于复杂的结果集映射,缓存上一层的父对象
* 例如,正在映射allResultMap -> User , 由于现在是处理嵌套映射,那么当映射Role的时候使用的父对象必然是在User对象
* 缓存父对象主要是为了解决循环依赖,例如在User中包含Role,在Role中又包含User
* <pre>
* 案例
* <resultMap id="allResultMap" type="Users">
* <association property="roles" javaType="Roles" resultMap="roleResultMap">
* <id property="id" column="id"/>
* 此时,Roles对象中,又引用了allResultMap,也就是User对象这个ResultMap
* <association property="users" javaType="Users" resultMap="allResultMap"/>
* </association>
* </resultMap>
* </pre>
* 因此在执行User的嵌套属性映射Role时候,需要将User对象缓存,到时候Role映射完之后,设置到该User对象中,如果不缓存,每次创建对象
* <pre>
* 例如: class User{
* Role role;
* }
* class Role{
* User user;
* }
* </pre>
*/
public Map<String, Object> ancestorObjects = new HashMap<>();
// 前一行的的值,用于处理多结果集
public Object previousRowValue;
/**
* 多个结果集的情况下使用
* 正在映射的属性列指定了要从某个结果集中获取数据,但是该结果集暂时没有执行到,因此需要暂存这个属性的映射信息
* key: 指定的结果集名称,value: 该属性的映射信息
* <pre>
* <select id="selectBlog" resultSets="blogs,authors" resultMap="blogResult" statementType="CALLABLE">
* {call getBlogsAndAuthors(#{id,jdbcType=INTEGER,mode=IN})}
* </select>
*
* <resultMap id="blogResult" type="Blog">
* <id property="id" column="id" />
* <association property="author" javaType="Author" resultSet="authors" resultMap="authorMap" column="author_id" foreignColumn="id">
* <id property="id" column="id"/>
* </association>
* </resultMap>
* </pre>
*/
// key: 结果集名称,该结果集需要与那个字段进行映射
public Map<String, ResultMapping> nextResultMaps = new HashMap<>();
// 缓存指定了要使用某一个结果集进行结果映射但是该结果集还未被处理的那些字段信息
// 例如: 存在多个结果集A1,A2,处理A1结果集的时候,有resultMap中的字段指定了要使用A2的结果集中的字段进行映射
// 此时,会为A1结果集创建一个缓存Key,缓存该结果集挂起(也就是指定了A2结果的)的所有的字段映射信息
public Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<>();
// 缓存指定的resultMap中,可以自动映射成功的列名信息
// key: resultMapId[前缀],所有映射成功的列名
public Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<>();
// 保存所有通过构造函数名称自动映射的列名信息
// key: resultMap.getId() + ":" + columnPrefix
public Map<String, List<String>> constructorAutoMappingColumns = new HashMap<>();
// 临时标记标志,表示当前结果对象使用了构造函数映射
public boolean useConstructorMappings;
// 处理多结果集,多结果集需要驱动支持
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
// 兼容多结果集的处理方案,每一个元素都是一个结果集中的结果
final List<Object> multipleResults = new ArrayList<>();
// 结果集的数量
int resultSetCount = 0;
// 获取查询返回结果集中的第一个结果集对象,因为可能存在多个结果集的情况
ResultSetWrapper rsw = this.getFirstResultSet(stmt);
// 所有该映射语句使用的所有resultMap,可能有多个
List<ResultMap> resultMaps = mappedStatement.resultMaps;
// resultMap个数
int resultMapCount = resultMaps.size();
// 如果存在结果集的情况下,必须需要resultMap,否则抛出异常
// 正常情况下都会有
this.validateResultMapsCount(rsw, resultMapCount);
/**
* 将结果集与resultMap进行映射,如果只有一个结果集和一个resultMap,这也是最常见的映射,那么直接拿当前结果集使用resultMap进行映射就行
* 但是,结果集和resultMap都可以有多个,那么如何映射呢?
* 1. 如果结果集与resultMap的数量一致的话,那么,一个结果集使用一个resultMap进行映射,处理完之后,此时while循环终止,rsw结果集对象为空
* 2. 如果结果集与resultMap的数量不一致的话,又有两种情况
* 2.1 结果集多,resultMap少,一个结果集使用一个resultMap进行映射,当while循环终止的时候,此时多出来结果集对象还未处理,这种情况下面会有一个循环专门处理
* 2.2 resultMap多,结果集少,一个结果集使用一个resultMap进行映射,当while循环终止的时候,rsw结果集对象为空,多出来的resultMap会被忽略
*/
while (rsw != null && resultMapCount > resultSetCount) {
// 获取该映射语句的ResultMap结果集映射信息
ResultMap resultMap = resultMaps.get(resultSetCount);
// 处理结果集的映射关系
this.handleResultSet(rsw, resultMap, multipleResults, null);
// 获取下一个结果集进行处理
rsw = getNextResultSet(stmt);
// 处理结果集后的清理上一次的结果映射相关的缓存数据
cleanUpAfterHandlingResultSet();
// 处理的结果集数量+1
resultSetCount++;
}
/**
* 处理上面注释中2.1中剩下的结果集对象,由于上一个结果集进行字段映射的时候,某字段可能指定了要与当前暂未进行映射的结果集来映射
* 例如: 该sql会产生两个结果集,分别是blogs,authors,首先肯定是将结果集blogs与resultMap(blogResult)进行映射
* 在这个过程中,blogResult映射author字段的时候,该字段指定了要使用authors来映射,那他是如何完成的呢?
* 1. 首先在上面这个循环会处理blogs这个结果集与blogResult这个ResultMap进行映射,映射到author字段的时候,发现该字段要使用authors进行映射
* 但是此时当前结果集blogs还没有处理完,因此将author(字段映射)->authors(结果集)的映射关系进行了挂起
* 而挂起的字段映射到结果集的关系保存到{@link nextResultMaps}这个Map中,具体挂起的逻辑参考
* {@link ResultSetHandler.DefaultResultSetHandler#getPropertyMappingValue)
* {@link ResultSetHandler.DefaultResultSetHandler#addPendingChildRelation)
* <pre>
* <select id="selectBlog" resultSets="blogs,authors" resultMap="blogResult" statementType="CALLABLE">
* {call getBlogsAndAuthors(#{id,jdbcType=INTEGER,mode=IN})}
* </select>
*
* <resultMap id="blogResult" type="Blog">
* <association property="author" javaType="Author" resultSet="authors" resultMap="authorMap" column="author_id" foreignColumn="id"/>
* </resultMap>
* </pre>
*/
// 获取该映射语句设置的结果集对象
String[] resultSets = mappedStatement.resultSets;
// 如果设置了,就需要处理
if (resultSets != null) {
// 当结果集对象不为空,表示结果集个数多于resultMap数量,就要处理上一个结果集映射中,挂起的字段映射
while (rsw != null && resultSetCount < resultSets.length) {
// 根据当前结果集的名称,找到在上一个结果集映射的过程中,依赖该结果集而挂起的映射字段信息
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
// 如果存在引用当前结果集被挂起的字段映射信息
if (parentMapping != null) {
// 因为能被挂起的只有association或者colllection,这两个标签才能个指定从结果集中映射
// 而association使用的结果集是嵌套的resultMap,因此parentMapping.nestedResultMapId就是获取在association指定的resultMap
String nestedResultMapId = parentMapping.nestedResultMapId;
// 获取association要使用的resultMap信息
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
// 开始进行结果集映射,正好就是挂起的字段和指定的结果集进行映射
handleResultSet(rsw, resultMap, null, parentMapping);
}
// 继续获取下一个结果集,将所有结果集都处理完
rsw = getNextResultSet(stmt);
// 处理结果集后的清理上一次的缓存操作
cleanUpAfterHandlingResultSet();
// 处理的结果集数量+1
resultSetCount++;
}
}
// 处理单结果集的情况,如果是单结果集,将结果集对象的第一个元素返回,如果存在多个结果集,将所有处理的结果集对象返回
return collapseSingleResultList(multipleResults);
}
// 处理游标的多结果集
@Override
public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
// 获取第一个结果集对象
ResultSetWrapper rsw = this.getFirstResultSet(stmt);
// 获取该映射语句的所有结果集映射
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
// 结果集映射的个数
int resultMapCount = resultMaps.size();
// 如果存在结果集的情况下,必须需要resultMap,否则抛出异常
this.validateResultMapsCount(rsw, resultMapCount);
// 并且结果集对象必须只有一个
if (resultMapCount != 1) {
throw new ExecutorException("Cursor results cannot be mapped to multiple resultMaps");
}
// 获取到resultMap信息
ResultMap resultMap = resultMaps.get(0);
// 包装成默认的游标对象返回
return new DefaultCursor<>(this, resultMap, rsw, rowBounds);
}
// 处理存储过程的输出参数
public void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam) throws SQLException {
if (rs == null) {
return;
}
// 获取引用的resultMap
String resultMapId = parameterMapping.getResultMapId();
// 获取字段映射信息
ResultMap resultMap = configuration.getResultMap(resultMapId);
// 包装ResultSet
ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
// 如果不存在自定义的结果处理器
if (this.resultHandler == null) {
// 创建默认的结果处理器
ResultHandler resultHandler = new ResultHandler.DefaultResultHandler(objectFactory);
// 映射每一个行记录到目标结果对象中
// 进行结果映射
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
// 将结果处理器中处理的结果设置到参数对象中
metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
}
// 如果存在自定义的结果处理器
else {
// 映射每一个行记录到目标结果对象中
// 进行结果映射
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
}
// 关闭结果集
closeResultSet(rs);
}
// 处理存储过程输出参数
@Override
public void handleOutputParameters(CallableStatement cs) throws SQLException {
// 获取参数对象
Object parameterObject = parameterHandler.getParameterObject();
MetaObject metaParam = configuration.newMetaObject(parameterObject);
// 获取参数映射信息
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// 遍历所有的参数映射信息
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
// 如果参数模式是OUT或者INOUT(只有存储过程才会是这两个值)
if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
// 列参数映射的java类型是否是ResultSet
if (ResultSet.class.equals(parameterMapping.getJavaType())) {
// 处理存储过程的输出参数
handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
} else {
// 如果java类型是其他类型,获取该映射信息中设置的类型转换器
TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
// 使用类型转换器将该列的值进行转换,设置到参数对象中
metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
}
}
}
}
// 处理结果集后的清理上一次的缓存操作
public void cleanUpAfterHandlingResultSet() {
nestedResultObjects.clear();
}
public List<Object> collapseSingleResultList(List<Object> multipleResults) {
return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
}
/**
* 处理结果集的映射关系
* <pre>
* @param rsw 结果集对象
* @param resultMap 结果集需要使用的resultMap
* @param multipleResults 保存多个结果集的集和
* @param parentMapping 其他情况都为null,只有在多结果集的情况下才会出现值,因为多结果集中可能出现正在映射的列指定了要从某个结果集中获取数据进行映射,例如下面这种情况
* 因为处理结果集的时候是一一处理,当处理blogs结果集的时候,存在author字段,该字段指定了要从authors结果集中获取数据进行映射
* 那么这种情况,正在处理的blogs结果集肯定是无法完成的,只能等到处理authors结果集的时候,再将author这个映射列信息拿出来进行映射
* <select id="selectBlog" resultSets="blogs,authors" resultMap="blogResult" statementType="CALLABLE">
* {call getBlogsAndAuthors(#{id,jdbcType=INTEGER,mode=IN})}
* </select>
* <resultMap id="blogResult" type="Blog">
* <id property="id" column="id" />
* <association property="author" javaType="Author" resultSet="authors" resultMap="authorMap" column="author_id" foreignColumn="id">
* <id property="id" column="id"/>
* </association>
* </resultMap>
* </pre>
*/
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
// 如果parentMapping不为空,只会存在多结果集的情况下,表示上一个结果集(A)处理的时候,有映射字段标记了需要是有当前结果集(B)进行数据映射
// 例如: 首先处理的a结果集,但是a结果集的映射信息中存在<association property="author" javaType="Author" resultSet="b" resultMap="a" column="author_id" foreignColumn="id"/>
// 而当前的ResultSet则是b结果集,所以要将之前挂起的author的字段信息拿出来在当前b结果集中进行映射
if (parentMapping != null) {
// 处理被挂起的字段的映射信息
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
}
// 单个结果集的情况
// 没有指定自定义的结果处理器,注意: 如果方法参数中存在结果处理器,那么方法必须是返回void才会生效,否则resultHandler参数也是为null
else if (resultHandler == null) {
// 创建默认的结果处理器
ResultHandler.DefaultResultHandler defaultResultHandler = new ResultHandler.DefaultResultHandler(objectFactory);
// 处理结果集映射
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
// 保存处理好的结果,最终要返回给用户
multipleResults.add(defaultResultHandler.getResultList());
}
// 单个结果集的情况
// 注意: 如果方法参数中存在结果处理器,那么方法必须是返回void才会生效,否则resultHandler参数也是为null
// 如果指定了结果处理器,那么只会将每一行结果交给处理器处理,最终并不会将结果返回给用户
else {
// 处理结果集映射
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
// 关闭结果集
closeResultSet(rsw.getResultSet());
}
// 关闭结果集
public void closeResultSet(ResultSet rs) {
if (rs != null) {
rs.close();
}
}
// 映射每一个行记录到目标结果对象中
// 进行结果映射
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
// 当前映射语句的resultMap中是否存在嵌套的resultMap
// 在resultMap标签中,如果具有"association", "collection", "case"其中的一个,那么就是嵌套的resultMap,因为在这些标签内部,也可以填写与resultMap完全一样的映射关系
if (resultMap.hasNestedResultMaps()) {
// 校验分页的边界问题
ensureNoRowBounds();
// 校验带有嵌套结果映射的映射语句不能与自定义ResultHandler一起使用
checkResultHandler();
// 通过行数据填充嵌套的resultMap
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
// 如果是一个简单的映射类型,单独的resultMap或者resultType
else {
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
// 如果是一个简单的映射类型,单独的resultMap或者resultType
public void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
// 创建结果上下文
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
// 获取结果集对象
ResultSet resultSet = rsw.getResultSet();
// 分页跳到指定的行,处理offset
skipRows(resultSet, rowBounds);
// 是否需要继续处理结果还是需要停止处理(上下文对象没有设置停止处理结果集,并且处理的结果数量没有达到分页限制)
// 并且结果集未关闭且有值的情况才会继续处理
while (this.shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
// 处理discriminator,因此如果存在discriminator,则要使用discriminator中value对应的那个resultMap,那个resultMap对原始的resultMap和case的映射列进行了合并
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
// 创建该resultMap的返回类型对象并且使用当前结果集行的值进行映射
Object rowValue = this.getRowValue(rsw, discriminatedResultMap, null);
// 将该行的值保存到上下文对象中,通过结果执行器处理,或者存在多结果集的情况下是将当前行的结果设置到上一个结果集被挂起的对象属性中
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
/**
* 将该行的值保存到上下文对象中,通过结果执行器处理,或者存在多结果集的情况下是将当前行的结果设置到上一个结果集被挂起的对象属性中
* <pre>
* @param resultHandler 行结果处理器
* @param resultContext 结果上下文
* @param rowValue 当前行的值
* @param parentMapping 其他情况都为null,只有在多结果集的情况下才会出现值,因为多结果集中可能出现正在映射的列指定了要从某个结果集中获取数据进行映射,例如下面这种情况
* 因为处理结果集的时候是一一处理,当处理blogs结果集的时候,存在author字段,该字段指定了要从authors结果集中获取数据进行映射
* 那么这种情况,正在处理的blogs结果集肯定是无法完成的,只能等到处理authors结果集的时候,再将author这个映射列信息拿出来进行映射
* <select id="selectBlog" resultSets="blogs,authors" resultMap="blogResult" statementType="CALLABLE">
* {call getBlogsAndAuthors(#{id,jdbcType=INTEGER,mode=IN})}
* </select>
* <resultMap id="blogResult" type="Blog">
* <id property="id" column="id" />
* <association property="author" javaType="Author" resultSet="authors" resultMap="authorMap" column="author_id" foreignColumn="id">
* <id property="id" column="id"/>
* </association>
* </resultMap>
* @param rs 正在处理的结果集对象
* @throws SQLException
* </pre>
*/
public void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
// 如果parentMapping不为空,只会存在多结果集的情况下,表示上一个结果集(A)处理的时候,有映射字段标记了需要是有当前结果集(B)进行数据映射
// 例如: 首先处理的a结果集,但是a结果集的映射信息中存在<association property="author" javaType="Author" resultSet="b" resultMap="a" column="author_id" foreignColumn="id"/>
// 而当前的ResultSet则是b结果集,所以要将之前挂起的author的字段信息拿出来在当前b结果集中进行映射
if (parentMapping != null) {
// 将挂起的映射信息拿出来到当前结果集中进行映射
linkToParents(rs, parentMapping, rowValue);
}
// 如果不存在多结果集的情况下,直接使用结果处理器处理结果
else {
callResultHandler(resultHandler, resultContext, rowValue);
}
}
// 处理嵌套的结果映射
public void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
// 创建默认的结果上下文对象
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
// 获取结果集对象
ResultSet resultSet = rsw.getResultSet();
// 分页跳到指定的行,处理offset
skipRows(resultSet, rowBounds);
// 前一行的的值,用于处理多结果集
Object rowValue = previousRowValue;
// 是否需要继续处理结果还是需要停止处理(上下文对象没有设置停止处理结果集,并且处理的结果数量没有达到分页限制)
// 并且结果集未关闭且有值的情况才会继续处理
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
// 处理Discriminator类型的嵌套resultMap,按照分支来决定使用的ResultMap
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
// 创建缓存这一行结果的缓存KEY
CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
// 通过该缓存的key来确定这些要映射的列是否在行记录中有重复的记录
// 如果有,则直接获取出来,而不需要去创建新对象
Object partialObject = nestedResultObjects.get(rowKey);
// 该属性决定是否使用查询结果进行映射
// 如果为true: 那么结果映射的时候会按照sql的查询列的顺序进行一一映射
// 如果为false: 那么就会按照resultMap设置的列的顺序进行映射
if (mappedStatement.resultOrdered) {
// 如果没有缓存嵌套结果,并且上一行存在值
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;
}
// 如果不需要有序进行映射,或者中断处理结果了,则将当前行数据保存起来,保存到previousRowValue中
else if (rowValue != null) {
previousRowValue = rowValue;
}
}
// 从单行记录中创建结果对象,会解析属性的嵌套映射,使用递归操作
public Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException {
// 获取resultMapId
String resultMapId = resultMap.getId();
// 已经缓存的行的值,如果没有缓存,则为null
Object rowValue = partialObject;
// 如果已经缓存了当前行的对象,表示处理过类似的数据
if (rowValue != null) {
// 封装为元数据信息
MetaObject metaObject = configuration.newMetaObject(rowValue);
// 将当前行的结果缓存起来,key为resultMapId
// 因为接下来要执行嵌套字段映射,需要用到,因为嵌套映射就是子属性映射,所以要将当前父对象缓存,在真正执行子属性映射的时候,可以映射完成的结果设置到父对象中
// 每一个复杂属性association,collection都会对应一个resultMap,因此使用resultMapId作为缓存Key
// 缓存父对象主要是为了解决循环依赖,例如在User中包含Role,在Role中又包含User
putAncestor(rowValue, resultMapId);
// 执行嵌套的resultMap字段映射
applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
// 处理了完了该属性的嵌套映射,将缓存的该resultMap对应的对象删除
ancestorObjects.remove(resultMapId);
}
// 如果没有缓存结果对象,则需要创建这一行的结果对象
else {
// 保存所有懒加载的属性的集合
ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 创建当前行的结果对象
rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
// 如果创建了当前行对应的结果对象,但是不存在这个结果对象的类型转换器
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
// 封装成结果对象的元数据信息
MetaObject metaObject = configuration.newMetaObject(rowValue);
// 是否找到了可以映射的值
boolean foundValues = this.useConstructorMappings;
// 是否需要进行自动映射
if (shouldApplyAutomaticMappings(resultMap, true)) {
// 执行自动映射操作,将未能映射上的列或者没有设置映射关系的列尝试进行自动映射
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
// 再执行在resultMap中标记的属性映射
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
// 将当前行的结果缓存起来,key为resultMapId
// 因为接下来要执行嵌套字段映射,需要用到,因为嵌套映射就是子属性映射,所以要将当前父对象缓存,在真正执行子属性映射的时候,可以映射完成的结果设置到父对象中
// 每一个复杂属性association,collection都会对应一个resultMap,因此使用resultMapId作为缓存Key
// 缓存父对象主要是为了解决循环依赖,例如在User中包含Role,在Role中又包含User
putAncestor(rowValue, resultMapId);
// 执行当前创建的结果对象中子属性的的嵌套映射
foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
// 处理了完了该属性的嵌套映射,将缓存的该resultMap对应的对象删除
ancestorObjects.remove(resultMapId);
// 存在懒加载的属性,或者找到了属性映射的值
foundValues = lazyLoader.size() > 0 || foundValues;
// 返回这一行结果集处理好的结果对象
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
// 如果存在合并的Key,将当前正在处理的resultMap的值缓存起来
// 正常情况下,同一个resultMap中的几乎所有的对象都会被缓存
if (combinedKey != CacheKey.NULL_CACHE_KEY) {
// 将当前行的结果进行缓存起来
nestedResultObjects.put(combinedKey, rowValue);
}
}
return rowValue;
}
// 创建该resultMap的返回类型对象并且使用当前结果集行的值进行映射
public Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
// 创建保存所有懒加载的属性的集合
ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 创建当前行的结果对象
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
// 如果创建了当前行对应的结果对象,但是不存在这个结果对象的类型转换器
if (rowValue != null && !this.hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
// 封装成结果对象的元数据信息
MetaObject metaObject = configuration.newMetaObject(rowValue);
// 是否找到了可以映射的值
boolean foundValues = this.useConstructorMappings;
// 是否需要进行自动映射
if (this.shouldApplyAutomaticMappings(resultMap, false)) {
// 执行自动映射操作,将未能映射上的列或者没有设置映射关系的列尝试进行自动映射
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
// 再执行在resultMap中标记的属性映射
foundValues = this.applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
// 存在懒加载的属性,或者找到了属性映射的值
foundValues = lazyLoader.size() > 0 || foundValues;
// 返回这一行结果集处理好的结果对象
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
// 执行嵌套的结果字段映射
public boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
boolean foundValues = false;
// 遍历所有的字段映射
for (ResultMapping resultMapping : resultMap.propertyResultMappings) {
// 获取嵌套的resultMapId
// 获取在association或colllection指定的resultMap
// 因为只有association或者colllection这两个标签需要进行嵌套映射,其他的普通字段都没有
String nestedResultMapId = resultMapping.nestedResultMapId;
/**
* 如果存在嵌套的resultMap并且没有指定该属性映射需要从指定结果集获取结果进行映射才需要处理
* 其他情况,例如,简单字段映射,或者给association或colllection属性设置了resultSets在上面
* {@link ResultSetHandler.DefaultResultSetHandler#getPropertyMappingValue}中已经处理过,所以直接忽略
*/
if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
// 获取列前缀
String columnPrefix = this.getColumnPrefix(parentPrefix, resultMapping);
// 获取嵌套的resultMap信息
ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
// 处理嵌套查询中的循环引用,有前缀不会处理循环依赖
if (resultMapping.getColumnPrefix() == null) {
// 获取父对象,因为现在是处理嵌套属性(也就是子属性),那么父对象一定创建了
// 例如User对象包含Role属性,则现在处理Role对象的映射,那么User对象已经创建了
// 缓存父对象主要是为了解决循环依赖,例如在User中包含Role,在Role中又包含User
// 在执行当前applyNestedResultMappings方法之前,就已经将父对象与它对应的resultMapId缓存了
/**
* <pre>
* 案例 {@link ResultSetHandler.DefaultResultSetHandler#putAncestor}
* {@link ResultSetHandler.DefaultResultSetHandler#getRowValue}
* <resultMap id="allResultMap" type="Users">
* <association property="roles" javaType="Roles" resultMap="roleResultMap">
* <id property="id" column="id"/>
* 此时,Roles对象中,又引用了allResultMap,也就是User对象这个ResultMap
* <association property="users" javaType="Users" resultMap="allResultMap"/>
* </association>
* </resultMap>
* </pre>
*/
// 通过以上案例,就可以发现,User映射Role,而Role又映射User,此时映射的User使用的resultMap是最外层User的resultMap
// 而User的resultMap在执行当前方法之前,就已经将User的resultMapId->User对象缓存到ancestorObjects对象中了
// 因此,这个就能获取到之前缓存的User对象,然后直接设置到Role对象中,从而解决了循环依赖
Object ancestorObject = ancestorObjects.get(nestedResultMapId);
// 如果存在缓存的父对象才表示出现了循环依赖,才有必要进行设置值,否则就走正常的嵌套映射,创建该嵌套的resultMap的结果对象并进行映射
if (ancestorObject != null) {
// 如果是新创建的对象
if (newObject) {
// 将该父对象设置到结果对象中
// 将指定属性的值设置到结果对象中
linkObjects(metaObject, resultMapping, ancestorObject);
}
continue;
}
}
// 正式
// 如果存在列前缀,就要拼接该列前缀
// 创建这一行结果的唯一的缓存结果的KEY
CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
// 合并key,因为出现嵌套映射的时候,需要对父对象数据和子对象数据进行合并来确定是否存在缓存的记录
CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
// 嵌套结果对象,只要是处理过的嵌套的属性,都会缓存到nestedResultObjects中
Object rowValue = nestedResultObjects.get(combinedKey);
// 是否存在值缓存的值
boolean knownValue = rowValue != null;
// 初始化集合类型的字段值
this.instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory
// 是否在任何一个空列中存在值,也就是只要列存在数据,就可以
if (this.anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) {
// 递归设置子属性
rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue);
// 在递归设置属性之前,没有值但是递归之后又存在值,表示在递归操作中,处理好了这一条记录
if (rowValue != null && !knownValue) {
// 将嵌套属性的值设置到结果对象中
linkObjects(metaObject, resultMapping, rowValue);
// 标记找到了值
foundValues = true;
}
}
}
}
return foundValues;
}
// 调用结果处理器的执行逻辑
public void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
resultContext.nextResultObject(rowValue);
((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}
// 执行属性的映射
public boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
// 获取所有在resultMap中的column列名与结果集列名匹配的所有列名
List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
// 是否找到了映射的值
boolean foundValues = false;
// 获取所有的属性映射关系
List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
// 遍历所有的映射关系
for (ResultMapping propertyMapping : propertyMappings) {
// 拼接前缀
String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
// 如果存在嵌套映射
if (propertyMapping.getNestedResultMapId() != null) {
// 用户在嵌套属性中填写了列名,忽略,因为嵌套属性不是通过列名映射,要单独处理
column = null;
}
// 1. 会处理设置了column = {prop: column,prop: column}
// 2. 会处理设置了column属性 column ="id" 并且该结果集的列名与resultMap中标注的column一致
// 3. 会处理设置了column属性 column ="id" 并且属性映射中设置了使用指定的结果集
if (propertyMapping.isCompositeResult() || column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)) || propertyMapping.resultSet() != null) {
// 获取该属性映射的值,会处理嵌套查询和多结果集处理的值
Object value = this.getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
// 获取属性名
String property = propertyMapping.getProperty();
// 如果不存在属性名,不处理
if (property == null) {
continue;
}
// 如果值被标记为了延迟加载
// 出现了循环依赖,或者设置了懒加载
if (value == DEFERRED) {
// 标记找到了列值
foundValues = true;
continue;
}
// 如果未标记延迟加载,是正常映射的值
if (value != null) {
// 标记找到了列值
foundValues = true;
}
// 如果找到了正常映射的列值,将属性值设置到结果对象中
if (value != null || configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive()) {
metaObject.setValue(property, value);
}
}
}
// 返回是否找到了该列的值
return foundValues;
}
// 获取属性映射的值
public Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
// 是否存在嵌套查询,处理复杂属性(JavaBean)映射的情况才可能会有
if (propertyMapping.getNestedQueryId() != null) {
// 通过嵌套查询获取映射值
return this.getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
}
// 不存在嵌套查询
// 如果指定了要从某个结果集中获取值,只能在association,collection使用
// 也就是这个JavaBean的结果要从指定的结果集中获取数据进行映射
if (propertyMapping.getResultSet() != null) {
/**
* 如果指定了要从某个结果集中获取值,只能在association,collection使用
* 也就是这个JavaBean的结果要从指定的结果集中获取数据进行映射
* 例如,某个查询设置了结果会产生多个结果集,而映射关系的时候,association设置了该属性从某一个结果集中获取数据
* 处理结果的时候,是一个结果集一个结果集处理,如果指定的那个结果集还未处理到,那么要先保存这种映射关系,到处理它指定的那个结果集的时候就拿出来处理
*/
this.addPendingChildRelation(rs, metaResultObject, propertyMapping);
// 返回一个标识,该映射关系需要延迟处理
return DEFERRED;
}
// 未指定使用的结果集,直接通过类型转换器将当前列值进行转换
else {
// 获取映射指定的类型转换器
TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
// 拼接前缀
String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
// 使用类型转换器获取列值
return typeHandler.getResult(rs, column);
}
}
// 获取嵌套查询结果映射的值,如果是延迟加载或者懒加载,都会返回延迟加载的标识
public Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
// 获取嵌套查询ID
String nestedQueryId = propertyMapping.getNestedQueryId();
String property = propertyMapping.getProperty();
// 获取嵌套查询语句
MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
// 获取参数类型
Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
// 根据嵌套查询设置的column列名,从结果集中获取列值设置到参数对象中,供给嵌套查询对象使用
Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix);
Object value = null;
// 如果结果集列中的值为null,那么nestedQueryParameterObject就会为空,此时不会执行嵌套查询
if (nestedQueryParameterObject != null) {
// 获取嵌套查询的SQL信息
BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
// 创建缓存KEY
CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
Class<?> targetType = propertyMapping.getJavaType();
// 是否存在该查询的缓存结果,存在缓存结果
if (executor.isCached(nestedQuery, key)) {
// 使用延迟加载操作,该操作时使用嵌套查询解决循环依赖问题
// 当缓存数据中结果对象,则直接设置到目标结果对象中
// 如果缓存数据中不存在结果对象,此时将相关信息保存到延迟加载队列中
// 等主查询结束之后,统一将队列中所有的延迟加载的属性从缓存中获取数据进行属性设置
executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
// 返回延迟加载的标识
value = DEFERRED;
}
// 如果没有缓存该嵌套查询的结果
else {
// 创建结果加载器
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;
}
// 创建该resultMap的返回类型对象并且使用当前结果集行的值进行映射
public Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
// 重置之前的映射结果
this.useConstructorMappings = false;
// 构造函数参数类型
List<Class<?>> constructorArgTypes = new ArrayList<>();
// 构造函数参数对值
List<Object> constructorArgs = new ArrayList<>();
// 根据不同的条件创建目标对象,例如构造映射,返回接口等各种情况
Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
// 如果创建成功了对象,表示映射成功了
if (resultObject != null &&
// 如果创建结果对象成功之后
// 确定是否存在该结果对象的类型转换器,如果找到了结果对象的类型转换器,即使需要懒加载,也不会进行懒加载操作
// 如果不存在的情况下,要判断resultMap的映射字段中是否存在嵌套查询并且设置了懒加载的属性
// 如果设置嵌套查询并且设置了懒加载,要为该结果对象创建代理对象,使用代理对象执行懒加载操作
!this.hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
// 获取所有的属性映射
List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
// 遍历所有的属性映射
for (ResultMapping propertyMapping : propertyMappings) {
// 如果该映射为嵌套查询,并且设置为懒加载
// 此时要为结果对象创建代理对象,因为懒加载的情况下,需要在调用的时候才会执行SQL
if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
resultObject = configuration.proxyFactory.createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
break;
}
}
}
this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty();
return resultObject;
}
// 根据不同的条件创建目标对象,例如构造映射,返回接口等各种情况
public Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) throws SQLException {
// 获取resultMap的返回类型
Class<?> resultType = resultMap.getType();
// 包装成元数据类型
MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
// 获取构造参数映射
List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
// 存在该结果对象的类型转换器
if (this.hasTypeHandlerForResultObject(rsw, resultType)) {
// 直接使用类型转换器提供的对象
return this.createPrimitiveResultObject(rsw, resultMap, columnPrefix);
}
// 如果没有提供该结果对象的类型转换器
// 根据构造映射提供列名和列值找到对象的有参构造创建对象
if (!constructorMappings.isEmpty()) {
return this.createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
}
// 如果是接口或者有默认的构造函数,直接使用对象工厂进行创建对象
if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
return this.objectFactory.create(resultType);
}
// 如果还是不满足,判断是否需要进行自动映射
if (shouldApplyAutomaticMappings(resultMap, false)) {
// 找到所有的构造方法进行查找,找到可以进行映射的构造方法,如果没有找到,抛出异常
// 如果找到可用的构造方法,使用该构造方法进行映射
return this.createByConstructorSignature(rsw, resultMap, columnPrefix, resultType, constructorArgTypes, constructorArgs);
}
// 其他情况,无法创建对象,抛出异常
throw new ExecutorException("Do not know how to create an instance of " + resultType);
}
// 是否存在该结果对象的类型转换器
public boolean hasTypeHandlerForResultObject(ResultSetWrapper rsw, Class<?> resultType) {
// 如果结果只有一列
if (rsw.getColumnNames().size() == 1) {
// 判断是否有指定java类型并且指定JDBC类型的类型转换器
return typeHandlerRegistry.hasTypeHandler(resultType, rsw.getJdbcType(rsw.getColumnNames().get(0)));
}
// 判断是否有指定java类型的类型转换器
return typeHandlerRegistry.hasTypeHandler(resultType);
}
// 使用类型转换器提供的对象
public Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
// 获取resultMap最终要封装的java类型
Class<?> resultType = resultMap.getType();
String columnName;
// 如果该ResultMap存在字段映射
// 我们只需要获取第一个列名就可以,为什么?
// 首先,如果要返回的结果对象是一个简单类型,那么使用一个字段就足以得出结果对象
// 第二: 如果返回的对象是一个复杂类型,但是又存在类型转换器,而类型转换器通过某一个列名就能得到该结果对象,那么就算执行所有列名,还是只能返回一个结果对象
// 换句话说,当前只需要创建一个对象,而类型转换器就已经会提供这个对象,就算又多个列名,那该使用那个对象呢?,所以不管任何情况,有类型转换器的情况就直接执行一次就行
if (!resultMap.getResultMappings().isEmpty()) {
// 获取到所有的结果映射
List<ResultMapping> resultMappingList = resultMap.getResultMappings();
// 获取到第一个映射信息
ResultMapping mapping = resultMappingList.get(0);
// 拼接列名前缀
columnName = prependPrefix(mapping.getColumn(), columnPrefix);
} else {
// 如果不存在字段映射,直接获取第一个列名
columnName = rsw.getColumnNames().get(0);
}
// 获取该列的类型转换器
TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
// 通过类型转换器创建对象
return typeHandler.getResult(rsw.getResultSet(), columnName);
}
// 根据构造映射提供列名和列值找到对象的有参构造创建对象
public Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) {
boolean foundValues = false;
// 遍历所有构造映射信息
for (ResultMapping constructorMapping : constructorMappings) {
Class<?> parameterType = constructorMapping.getJavaType();
String column = constructorMapping.getColumn();
Object value;
// 如果存在嵌套查询
if (constructorMapping.getNestedQueryId() != null) {
// 获取嵌套查询的构造参数值
value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
}
// 如果不存在嵌套查询,但是存在嵌套映射
else if (constructorMapping.getNestedResultMapId() != null) {
// 获取到嵌套映射信息
ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
// 递归处理该映射信息
value = getRowValue(rsw, resultMap, getColumnPrefix(columnPrefix, constructorMapping));
}
// 不存在嵌套查询和嵌套结果集对象
else {
// 获取构造参数类型对应的类型转换器
TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
// 通过类型转换器获取该列的结果
value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
}
// 保存构造参数类型
constructorArgTypes.add(parameterType);
// 保存构造函数值
constructorArgs.add(value);
// 是否找到了构造参数
foundValues = value != null || foundValues;
}
// 根据找到的构造参数类型和构造参数值对应的有参构造创建对象
return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
}
// 获取嵌套查询的构造函数值
public Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix) throws SQLException {
// 获取嵌套查询ID
String nestedQueryId = constructorMapping.getNestedQueryId();
// 获取该嵌套查询的statement映射语句信息
MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
// 获取嵌套查询的参数类型
Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
// 根据嵌套查询设置的column列名,从结果集中获取列值设置到参数对象中,供给嵌套查询对象使用
Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping, nestedQueryParameterType, columnPrefix);
Object value = null;
// 如果结果集列中的值为null,那么nestedQueryParameterObject就会为空,此时不会执行嵌套查询
if (nestedQueryParameterObject != null) {
// 获取嵌套查询的SQL信息
BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
// 创建缓存KEY
CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
Class<?> targetType = constructorMapping.getJavaType();
// 使用加载器去加载属性
ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
// 执行嵌套查询操作
value = resultLoader.loadResult();
}
return value;
}
// 根据嵌套查询设置的column列名,从结果集中获取列值设置到参数对象中,供给嵌套查询对象使用
public Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
// 是否是符合字段{prop=col,prop=col}这中参数信息
if (resultMapping.isCompositeResult()) {
// 处理复合属性的参数对象,将列中的对应的列值设置到参数对象中
return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
}
// 通过参数类型获取对应的类型转换器,如果不存在该参数的类型转换器,使用万能的类型转换器从结果集对象中获取需要的值设置到结果参数对象中
return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
}
// 通过参数类型获取对应的类型转换器,如果不存在该参数的类型转换器,使用万能的类型转换器从结果集对象中获取需要的值设置到结果参数对象中
public Object prepareSimpleKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
TypeHandler<?> typeHandler;
// 如果存在该参数类型的类型转换器
if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
// 获取类型转换器
typeHandler = typeHandlerRegistry.getTypeHandler(parameterType);
} else {
// 获取未知类型的类型转换器
// 该对象是万能的,如果没有设置对应的java类型获取jdbc类型,它都会进行自动推断,如果没有根据java类型或者jdbc类型推断成功,则使用万能的ObjectTypeHandler
typeHandler = typeHandlerRegistry.getUnknownTypeHandler();
}
// 通过类型转换器获取生成结果对象
return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
}
// 处理复合属性的参数对象,将列中的对应的列值设置到参数对象中
public Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
// 根据参数类型实例化参数对象,如果指定了参数类型,那么创建参数类型的对象,否则都创建Map
Object parameterObject = instantiateParameterObject(parameterType);
// 封装为参数的元数据信息
MetaObject metaObject = configuration.newMetaObject(parameterObject);
boolean foundValues = false;
// 获取所有的复合映射列信息
for (ResultMapping innerResultMapping : resultMapping.composites) {
// 获取属性的类型
Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());
// 获取属性类型对应的类型转换器
TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);
// 通过类型转换器获取到对应的属性值
Object propValue = typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix));
// 如果获取到了属性值
if (propValue != null) {
// 将该属性值设置到参数对象中
metaObject.setValue(innerResultMapping.getProperty(), propValue);
foundValues = true;
}
}
// 返回处理好的参数对象
return foundValues ? parameterObject : null;
}
// 根据参数类型实例化参数对象,如果指定了参数类型,那么创建参数类型的对象,否则都创建Map
public Object instantiateParameterObject(Class<?> parameterType) {
if (parameterType == null) {
return new HashMap<>();
}
if (ParamMap.class.equals(parameterType)) {
return new HashMap<>();
} else {
return objectFactory.create(parameterType);
}
}
/**
* 只会出现在多结果集的情况下,将挂起的映射信息拿出来到当前结果集中进行映射
* {@link ResultSetHandler.DefaultResultSetHandler#storeObject}
*/
public void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
// 创建存在多个结果的缓存Key
CacheKey parentKey = this.createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn());
// 缓存指定了要使用某一个结果集进行结果映射但是该结果集还未被处理的那些字段信息
// 例如: 存在多个结果集A1,A2,处理A1结果集的时候,有resultMap中的字段指定了要使用A2的结果集中的字段进行映射
// 此时,会为A1结果集创建一个缓存Key,缓存该结果集挂起(也就是指定了A2结果的)的所有的字段映射信息
List<PendingRelation> parents = pendingRelations.get(parentKey);
// 如果存在挂起的映射列信息
if (parents != null) {
// 遍历所有挂起的映射关系
for (PendingRelation parent : parents) {
// 如果存在挂起的映射字段,并且当前行的值处理好了
if (parent != null && rowValue != null) {
// 将当前行的值设置到被挂起的字段中
linkObjects(parent.metaObject, parent.propertyMapping, rowValue);
}
}
}
}
/**
* 如果指定了要从某个结果集中获取值,只能在association,collection使用
* 也就是这个JavaBean的结果要从指定的结果集中获取数据进行映射
* 例如,某个查询设置了结果会产生多个结果集,而映射关系的时候,association设置了该属性从某一个结果集中获取数据
* <pre>
* <select id="selectBlog" resultSets="blogs,authors" resultMap="blogResult" statementType="CALLABLE">
* {call getBlogsAndAuthors(#{id,jdbcType=INTEGER,mode=IN})}
* </select>
*
* <resultMap id="blogResult" type="Blog">
* <id property="id" column="id" />
* <result property="title" column="title"/>
* <association property="author" javaType="Author" resultSet="authors" resultMap="authorMap" column="author_id" foreignColumn="id">
* <id property="id" column="id"/>
* <result property="username" column="username"/>
* </association>
* </resultMap>
* </pre>
* 处理结果的时候,是一个结果集一个结果集处理,如果指定的那个结果集还未处理到,那么要先保存这种映射关系,到处理它指定的那个结果集的时候就拿出来处理
*/
public void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping) throws SQLException {
// 创建这在处理的结果集的缓存Key
CacheKey cacheKey = this.createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getColumn());
// 创建延迟加载的映射信息,因为它要从指定结果集中获取数据
PendingRelation deferLoad = new PendingRelation(metaResultObject, parentMapping);
// 保存该延迟加载的列信息
List<PendingRelation> relations = MapUtil.computeIfAbsent(pendingRelations, cacheKey, k -> new ArrayList<>());
relations.add(deferLoad);
// 查询是否缓存了该指定的结果集对应的映射列信息
ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
// 如果没有缓存
if (previous == null) {
// 缓存该结果集到该列的映射信息的关系
nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
}
// 如果存在两个不同的属性映射到同一个resultSet,抛出异常
else if (!previous.equals(parentMapping)) {
throw new ExecutorException("Two different properties are mapped to the same resultSet");
}
}
// 创建存在多个结果的缓存Key
public CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns) throws SQLException {
// 创建缓存Key
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;
}
// 找到所有的构造方法进行查找,找到可以进行映射的构造方法,如果没有找到,抛出异常
// 如果找到可用的构造方法,使用该构造方法进行映射
public Object createByConstructorSignature(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) throws SQLException {
// 执行构造映射
return applyConstructorAutomapping(rsw, resultMap, columnPrefix, resultType, constructorArgTypes, constructorArgs,
// 找到所有的构造方法进行查找,找到可以进行映射的构造方法,如果没有找到,抛出异常
findConstructorForAutomapping(resultType, rsw).orElseThrow(() -> new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames())));
}
// 查找构造函数来做自动映射操作
public Optional<Constructor<?>> findConstructorForAutomapping(Class<?> resultType, ResultSetWrapper rsw) {
// 获取所有的构造函数
Constructor<?>[] constructors = resultType.getDeclaredConstructors();
// 如果只有一个,返回
if (constructors.length == 1) {
return Optional.of(constructors[0]);
}
// 如果存在多个,找构造方法中是否存在@AutomapConstructor注解,如果在多个构造方法中标注,抛出异常
Optional<Constructor<?>> annotated = Arrays.stream(constructors)
.filter(x -> x.isAnnotationPresent(AutomapConstructor.class)).reduce((x, y) -> {
throw new ExecutorException("@AutomapConstructor should be used in only one constructor.");
});
// 如果找到唯一标注了@AutomapConstructor注解的构造方法,返回该构造函数
if (annotated.isPresent()) {
return annotated;
}
// 如果不存在@AutomapConstructor注解但是又配置了使用构造参数名称进行映射,抛出异常
if (configuration.argNameBasedConstructorAutoMapping) {
throw new ExecutorException(MessageFormat.format("'argNameBasedConstructorAutoMapping' is enabled and the class ''{0}'' has multiple constructors, so @AutomapConstructor must be added to one of the constructors.", resultType.getName()));
}
// 如果没有开启使用参数名进行映射,那么根据结果集中的JDBC类型匹配
// 通过构造参数类型去结果集中一一进行类型匹配,构造参数类型和列的jdbc类型全部匹配上才能用,否则不可用
return Arrays.stream(constructors).filter(x -> findUsableConstructorByArgTypes(x, rsw.getJdbcTypes())).findAny();
}
// 通过构造参数类型去结果集中一一进行类型匹配,构造参数类型和列的jdbc类型全部匹配上才能用,否则不可用
public boolean findUsableConstructorByArgTypes(Constructor<?> constructor, List<JdbcType> jdbcTypes) {
// 获取所有构造参数类型
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;
}
// 执行构造参数的自动映射
public Object applyConstructorAutomapping(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor) throws SQLException {
boolean foundValues = false;
// 是否开启了使用构造参数名称进行映射
if (configuration.argNameBasedConstructorAutoMapping) {
// 使用构造参数名称进行映射
foundValues = applyArgNameBasedConstructorAutoMapping(rsw, resultMap, columnPrefix, constructorArgTypes, constructorArgs, constructor, foundValues);
}
// 使用列顺序进行映射
else {
// 使用结果集列的顺序进行一一映射
foundValues = applyColumnOrderBasedConstructorAutomapping(rsw, constructorArgTypes, constructorArgs, constructor, foundValues);
}
// 如果找到值或者设置了结果集为null值需要使用默认对象代替的话,使用结果对象已经构造参数信息创建对象,否则直接返回hull
return foundValues || configuration.returnInstanceForEmptyRow ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
}
// 使用结果集列的顺序进行一一映射
public boolean applyColumnOrderBasedConstructorAutomapping(ResultSetWrapper rsw, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor, boolean foundValues) throws SQLException {
// 遍历所有的构造参数
for (int i = 0; i < constructor.getParameterTypes().length; i++) {
// 获取参数类型
Class<?> parameterType = constructor.getParameterTypes()[i];
// 获取列名
String columnName = rsw.getColumnNames().get(i);
// 获取参数java类型以及列名对应的类型转换器
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;
}
// 通过构造参数名称进行映射
public boolean applyArgNameBasedConstructorAutoMapping(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor, boolean foundValues) throws SQLException {
List<String> missingArgs = null;
// 获取构造函数的所有参数
Parameter[] params = constructor.getParameters();
// 遍历所有参数
for (Parameter param : params) {
boolean columnNotFound = true;
// 是否存在参数注解
Param paramAnno = param.getAnnotation(Param.class);
// 获取到要使用的参数名
String paramName = paramAnno == null ? param.getName() : paramAnno.value();
// 遍历所有的列名
for (String columnName : rsw.getColumnNames()) {
// 使用列名与参数名进行匹配,如果给定了前缀,拼接前缀进行匹配,同时会处理下划线转驼峰
if (this.columnMatchesParam(columnName, paramName, columnPrefix)) {
// 获取参数类型
Class<?> paramType = param.getType();
// 获取参数对应的类型转换器
TypeHandler<?> typeHandler = rsw.getTypeHandler(paramType, columnName);
// 获取转换后的结果
Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
// 保存到构造参数类型
constructorArgTypes.add(paramType);
// 保存构造参数的值
constructorArgs.add(value);
// 使用resultMap+列前缀作为
String mapKey = resultMap.getId() + ":" + columnPrefix;
// 如果缓存中不存在该Key的数据
if (!autoMappingsCache.containsKey(mapKey)) {
// 保存所有通过构造函数自动映射的列名信息进行缓存
MapUtil.computeIfAbsent(constructorAutoMappingColumns, mapKey, k -> new ArrayList<>()).add(columnName);
}
// 标记找到了映射的列名
columnNotFound = false;
// 标记是否找到了值对象
foundValues = value != null || foundValues;
}
}
// 如果没有找到映射的列名,将该列名先保存起来,后面需要校验
if (columnNotFound) {
if (missingArgs == null) {
missingArgs = new ArrayList<>();
}
missingArgs.add(paramName);
}
}
// 如果通过名称找了构造参数的值,但是根据构造参数名从列名中获取到的属性个数与实际参数不一致时,需要抛出异常
// 说白了就是我构造参数有3个,但是根据构造参数名在列数据中只找到了两个,这个时候抛出异常,如果一个都没有找到,则不会抛出异常
if (foundValues && constructorArgs.size() < params.length) {
throw new ExecutorException(MessageFormat.format(
"Constructor auto-mapping of ''{1}'' failed " + "because ''{0}'' were not found in the result set; "
+ "Available columns are ''{2}'' and mapUnderscoreToCamelCase is ''{3}''.",
missingArgs, constructor, rsw.getColumnNames(), configuration.isMapUnderscoreToCamelCase()));
}
return foundValues;
}
// 使用列名与参数名进行匹配,如果给定了前缀,拼接前缀进行匹配,同时会处理下划线转驼峰
public boolean columnMatchesParam(String columnName, String paramName, String columnPrefix) {
// 如果存在前缀
if (columnPrefix != null) {
// 列名需要拼接前缀进行匹配,如果列名不存在前缀,就没必要匹配了,肯定匹配不上
if (!columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
return false;
}
// 使用列名拼接前缀进行匹配
columnName = columnName.substring(columnPrefix.length());
}
// 如果配置了开启驼峰映射,则使用技巧,将列名的所有"_"删除之后,全部转换为小写来对比
return paramName.equalsIgnoreCase(configuration.isMapUnderscoreToCamelCase() ? columnName.replace("_", "") : columnName);
}
// 执行自动映射操作,将未能映射上的列或者没有设置映射关系的列尝试进行自动映射
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
// 创建未映射能映射成功的列名的自动映射信息(也就是在resultMap中的column列名与结果集列名不匹配的所有列名)
// 返回这些未能映射但是可以通过属性名自动映射的列名
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;
}
// 如果映射的值不为null,或者配置了无论值是否为空,都要设置(忽略简单类型)
if (value != null || configuration.callSettersOnNulls && !mapping.primitive) {
// 将属性设置到结果对象中
metaObject.setValue(mapping.property, value);
}
}
}
return foundValues;
}
// 创建未映射能映射成功的列名的自动映射信息(也就是在resultMap中的column列名与结果集列名不匹配的所有列名)
// 返回这些未能映射但是可以通过属性名自动映射的列名
public List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
// 缓存自动映射列信息的key
String mapKey = resultMap.getId() + ":" + columnPrefix;
// 之前是否缓存过该resultMap的自动映射的列信息
List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
// 如果没有缓存,就要开始创建自动映射的列信息
if (autoMapping == null) {
autoMapping = new ArrayList<>();
// 获取所有在resultMap中的column列名与结果集列名不匹配的所有列名(前提是填写了column属性)
List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
// 如果是当前结果对象是基于构造函数的自动映射创建的对象的话,会将自动映射的列名缓存到constructorAutoMappingColumns中
List<String> mappedInConstructorAutoMapping = constructorAutoMappingColumns.remove(mapKey);
// 先要排除构造映射的字段,不需要再映射构造字段
if (mappedInConstructorAutoMapping != null) {
unmappedColumnNames.removeAll(mappedInConstructorAutoMapping);
}
// 遍历所有未能映射成功的列名
for (String columnName : unmappedColumnNames) {
// 获取属性名,自动映射的情况下列名就是属性名
String propertyName = columnName;
if (columnPrefix != null && !columnPrefix.isEmpty()) {
// 当指定columnPrefix时,忽略没有前缀的列
if (!columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
continue;
}
// 拼接前缀
propertyName = columnName.substring(columnPrefix.length());
}
// 从结果对象中找该属性名对应的属性
String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
// 如果找到了,并且存在Set方法
if (property != null && metaObject.hasSetter(property)) {
// 在resultMap中字段映射设置的property属性名,如果设置property属性,保存到映射属性名的集合中
// 也就是设置了手动映射的字段要忽略
if (resultMap.mappedProperties.contains(property)) {
continue;
}
// 获取属性类型
Class<?> propertyType = metaObject.getSetterType(property);
// 是否存在该属性类型的类型转换器
if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {
// 获取类型转换器
TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
// 保存需要进行自动映射的列信息
autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));
}
// 如果自动映射的情况下,映射的属性并没有对应的类型转换器,也就无法进行转换
else {
// 执行无法映射列的行为操作
configuration.autoMappingUnknownColumnBehavior.doAction(mappedStatement, columnName, property, propertyType);
}
}
// 如果存在列名,但是并没有找到给列对应的属性
else {
// 执行无法映射列的行为操作
configuration.autoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName, property != null ? property : propertyName, null);
}
}
// 缓存该resultMap中,可以自动映射成功的列名信息
autoMappingsCache.put(mapKey, autoMapping);
}
return autoMapping;
}
// 是否需要进行自动映射
public boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
// 在resultMap中明确指定了自动映射的值
if (resultMap.getAutoMapping() != null) {
return resultMap.getAutoMapping();
}
// 如果是嵌套映射
// 指定MyBatis应如何自动映射列到字段或属性存在三个
// NONE 表示关闭自动映射;
// PARTIAL 只会自动映射没有定义嵌套结果映射的字段(默认)
// FULL 会自动映射任何复杂的结果集(无论是否嵌套)
if (isNested) {
return AutoMappingBehavior.FULL == configuration.autoMappingBehavior();
}
// 如果不是嵌套的话,只要没有关闭自动映射,那么就会使用自动映射
else {
return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
}
}
/**
* 嵌套ResultMap的父对象缓存,主要用于复杂的结果集映射,缓存上一层的父对象
* 例如,正在映射allResultMap -> User , 由于现在是处理嵌套映射,那么当映射Role的时候使用的父对象必然是在User对象
* 缓存父对象主要是为了解决循环依赖,例如在User中包含Role,在Role中又包含User
* <pre>
* 案例
* <resultMap id="allResultMap" type="Users">
* <association property="roles" javaType="Roles" resultMap="roleResultMap">
* <id property="id" column="id"/>
* 此时,Roles对象中,又引用了allResultMap,也就是User对象这个ResultMap
* <association property="users" javaType="Users" resultMap="allResultMap"/>
* </association>
* </resultMap>
* </pre>
* 因此在执行User的嵌套属性映射Role时候,需要将User对象缓存,到时候Role映射完之后,设置到该User对象中,如果不缓存,每次创建对象
* <pre>
* 例如: class User{
* Role role;
* }
* class Role{
* User user;
* }
* </pre>
*
* @param resultObject 缓存的结果对象
* @param resultMapId 该结果对象对应的resultMap,也就是在该resultMap的返回类型
*/
public void putAncestor(Object resultObject, String resultMapId) {
ancestorObjects.put(resultMapId, resultObject);
}
// 是否在任何一个非空列中存在值,也就是只要列存在数据,就可以
public boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSetWrapper rsw) throws SQLException {
// 获取所有的非空列的列名
Set<String> notNullColumns = resultMapping.notNullColumns;
// 如果存在非空列
if (notNullColumns != null && !notNullColumns.isEmpty()) {
// 获取结果集
ResultSet rs = rsw.getResultSet();
// 遍历列名
for (String column : notNullColumns) {
// 拼接前缀
String columnName = prependPrefix(column, columnPrefix);
// 获取该列的值
rs.getObject(columnName);
// 如果结果集不为空,表示该列不为空
if (!rs.wasNull()) {
return true;
}
}
// 没有列存在数据
return false;
}
// 如果没用设置非空列,但是设置了前缀,使用前缀比较
if (columnPrefix != null) {
// 遍历结果集中所有的列
for (String columnName : rsw.getColumnNames()) {
// 如果结果集中包含了以指定前缀开头的字段,则返回true
if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix.toUpperCase(Locale.ENGLISH))) {
return true;
}
}
return false;
}
// 如果前缀也没有设置,直接返回true
return true;
}
// 将指定属性的值设置到结果对象中
public void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue) {
// 初始化集合属性,如果是集合类型的字段,并且结果也是集合类型,那么直接赋值,如果不是集合类型,则创建空集合对象,其他类型返回null
Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
// 如果该字段是集合类型,那么将当前列的值保存到集合对象中
if (collectionProperty != null) {
MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
targetMetaObject.add(rowValue);
}
// 如果当前列的值不是集合,则直接将值设置到对象中
else {
metaObject.setValue(resultMapping.getProperty(), rowValue);
}
}
// 根据resultMapId从配置类中ResultMap信息
public ResultMap getNestedResultMap(ResultSet rs, String nestedResultMapId, String columnPrefix) throws SQLException {
// 从配置类中获取该ID对应的resultMap
ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId);
// 处理Discriminator,按照分支来决定使用的ResultMap
return resolveDiscriminatedResultMap(rs, nestedResultMap, columnPrefix);
}
// 获取列的前缀
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);
}
// 初始化集合属性,如果是集合类型的字段,并且结果也是集合类型,那么直接赋值,如果不是集合类型,则创建空集合对象,其他类型返回null
public Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {
// 获取属性名
String propertyName = resultMapping.getProperty();
// 获取属性值
Object propertyValue = metaObject.getValue(propertyName);
// 如果不存在属性值
if (propertyValue == null) {
// 获取映射关系的java类型
Class<?> type = resultMapping.getJavaType();
// 如果为设置java类型
if (type == null) {
// 使用结果对象中属性名对应的类型
type = metaObject.getSetterType(propertyName);
}
// 如果属性对应的类型为集合
if (objectFactory.isCollection(type)) {
// 创建集合对象
propertyValue = objectFactory.create(type);
// 将创建的结合设置到结果对象中
metaObject.setValue(propertyName, propertyValue);
// 返回创建的结果对象
return propertyValue;
}
}
// 如果存在属性值,并且属性值为集合类型,直接返回该值
else if (objectFactory.isCollection(propertyValue.getClass())) {
return propertyValue;
}
// 如果存在值,但是属性类型不是集合,无法赋值,返回hull
return null;
}
/**
* 因为是嵌套关系,因此将嵌套处理过程的中数据进行缓存,这里创建缓存的Key
* 在不同情况下,使用不同的数据作为缓存Key,这个缓存key是有讲究的
* <pre>
* 例如: 在这个嵌套结果集的情况下:
* uid username role_name permissions_name
* 1 luck admin select
* 1 luck admin delete
* 1 luck admin update
* 1 luck admin insert
*
* 映射为下面的结果,我们只想映射为一个User对象
* class User{
* Long uid;
* String username;
* Role role;
* List<Permission> permissions;
* }
* 先创建User对象, 映射uid和username字段
* 接着可以通过uid=1 username=luck 作为一级缓存的key
* 在映射role属性的时候 映射role_name
* 接着可以通过 uid=1 username=luck role_name=admin 作为二级缓存的key(也就是一级缓存的key+二级缓存的字段)
* 接着映射permissions属性的时候,映射permissions_name
* 接着可以通过 uid=1 username=luck permissions_name = [select,delete,update,insert] 作为另一个二级缓存的key(也就是一级缓存的key+二级缓存的字段)
* 这个时候,当我们处理好了这些高阶的缓存(role或者permission)之后,此时可以为user设置属性
* 我们根据每一个行的uid=1 username=luck role_name=admin来从缓存中获取数据都能获取到第一次缓存进去的数据,这样role对象只需要创建一次
* 我们根据每一个行的
* uid=1 username=luck permissions_name=select
* uid=1 username=luck permissions_name=delete
* uid=1 username=luck permissions_name=update
* uid=1 username=luck permissions_name=insert
* 来从缓存中获取数据,都是获取不到的,因此对于每一个permission对象,都需要创建新的,因此会有四个permission对象,一个role对象
* 而我们根据每一个行的uid=1 username=luck来从缓存中获取数据也都能获取到第一次缓存进去的user数据,这样user对象只需要创建一次
* 一次最终创建的结果就是user对象一个,role对象一个,permission对象4个,组成了User类的这种关系
*
* 当然,如何设置了id映射,那么就不需要缓存这么多字段的映射信息,只需要将id属性缓存即可,因为id属性是不会重复的,相同的id为相同的一组是正常的
*
*
* 1. 在resultMap中没有填写任何字段映射的情况下,有两种情况
* 1.1. 如果resultMap的返回类型是Map,那么缓存Key的数据为结果集中的所有键值对(列名和列值)
* 1.2. 如果resultMap返回的不是Map,而是一个普通对象,那么缓存key的数据为 在使用的resultMap中,未使用column指定要映射的列名的列和列值
* 2. 在resultMap指定了映射字段的情况下
* 2.1. 那么缓存key的数据为: 在使用的resultMap中,使用column指定了要映射的列名的列和列值作为缓存Key的数据
* </pre>
*
* @param resultMap 正在处理的resultMap映射
* @param rsw 结果集包装对象
* @param columnPrefix 列名前缀
* @return 缓存的Key信息
*/
public CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {
CacheKey cacheKey = new CacheKey();
// resultMapId
cacheKey.update(resultMap.getId());
// 获取该结果集映射中的映射关系,先获取ID类型的列映射,果不存在ID类型的列映射,则获取所有的普通属性映射
List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);
// 如果该result没有填写任何列映射信息
if (resultMappings.isEmpty()) {
// 如果resultMap需要返回的是Map类型,最简单,就是将列名映射到列名的值
if (Map.class.isAssignableFrom(resultMap.getType())) {
// 创建这一行结果的缓存Key
// 将结果集中所有列名和列值都作为缓存key中的一部分
this.createRowKeyForMap(rsw, cacheKey);
} else {
// 如果不是返回的不是Map,是某个对象
// 创建这一行结果的缓存Key
// 使用所有在resultMap中,未使用column指定要映射的列名的列和列值作为缓存Key的数据
this.createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
}
}
// 如果存在resultMap的映射字段信息
else {
// 创建这一行结果的缓存Key
// 使用所有在resultMap中,使用column指定了要映射的列名的列和列值作为缓存Key的数据
this.createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
}
// 因为设置缓存key的时候是一组一组的设置,所以如果小于2,表示数据缺失,则返回一个固定的空缓存KEY
if (cacheKey.getUpdateCount() < 2) {
return CacheKey.NULL_CACHE_KEY;
}
// 正常情况返回创建并处理好的缓存key
return cacheKey;
}
// 获取该结果集映射中的映射关系,先获取ID类型的列映射,果不存在ID类型的列映射,则获取所有的普通属性映射
public List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) {
// 先获取ID类型的列映射
List<ResultMapping> resultMappings = resultMap.getIdResultMappings();
// 如果不存在ID类型的列映射,则获取所有的普通属性映射
if (resultMappings.isEmpty()) {
resultMappings = resultMap.getPropertyResultMappings();
}
return resultMappings;
}
// 使用所有在resultMap中,使用column指定了要映射的列名的列和列值作为缓存Key的数据
public void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, List<ResultMapping> resultMappings, String columnPrefix) throws SQLException {
// 遍历所有映射关系
for (ResultMapping resultMapping : resultMappings) {
// 如果是简单的resultMap映射,不存在嵌套resultMap或者嵌套查询
if (resultMapping.isSimple()) {
// 拼接列前缀
String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
// 获取指定的类型转换器
TypeHandler<?> th = resultMapping.getTypeHandler();
// 获取所有在resultMap中的column列名与结果集列名匹配的所有列名(前提是填写了column属性)
List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
// 如果拼接上前缀之后,在映射的列名中存在,表示可以映射
if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {
// 使用类型转换器对该列的值进行类型转换
Object value = th.getResult(rsw.getResultSet(), column);
// 如果获取到列值,或者配置类设置了即使没有值也会返回空实例对象
// 将列名和列值当做缓存key
if (value != null || configuration.isReturnInstanceForEmptyRow()) {
cacheKey.update(column);
cacheKey.update(value);
}
}
}
}
}
// 创建这一行结果的缓存Key
// 所有在resultMap中的column列名与结果集列名不匹配的所有列名(前提是填写了column属性)列名的列和列值作为缓存Key的数据
public void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, String columnPrefix) throws SQLException {
// 根据resultMap的返回类型封装成可动态反射操作的class元数据
MetaClass metaType = MetaClass.forClass(resultMap.getType(), reflectorFactory);
// 获取所有在resultMap中的column列名与结果集列名不匹配的所有列名(前提是填写了column属性)
List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
// 遍历所有未映射上的列名
for (String column : unmappedColumnNames) {
String property = column;
if (columnPrefix != null && !columnPrefix.isEmpty()) {
// 当指定columnPrefix列前缀时,忽略没有指定前缀的列
if (!column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
continue;
}
// 使用列名拼接前缀
property = column.substring(columnPrefix.length());
}
// 在结果对象中找对应的属性(根据配置信息,会将列名的下换线转驼峰)
// 由于resultMap中的列和结果集中的列没有匹配上,那么,尝试使用列名和结果对象的属性匹配一下
// 如果属性匹配成功,那么就会绕过resultMap,直接使用属性映射
// 如果在结果对象中也没有找到该列对应的属性,则会忽略该字段
if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {
// 如果找到该列名映对应的属性,获取该列的值
String value = rsw.getResultSet().getString(column);
// 将列名和列值当做缓存key
if (value != null) {
cacheKey.update(column);
cacheKey.update(value);
}
}
}
}
// 创建这一行结果的缓存Key
// 将所有列名和列值都作为缓存key中的一部分
public void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException {
// 获取所有列名
List<String> columnNames = rsw.getColumnNames();
// 遍历所有列名
for (String columnName : columnNames) {
// 获取列值
String value = rsw.getResultSet().getString(columnName);
// 如果存在列值
if (value != null) {
// 缓存列名和列名
cacheKey.update(columnName);
cacheKey.update(value);
}
}
}
// 将指定属性的值设置到结果对象中
public void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue) {
// 初始化集合属性,如果是集合类型的字段,并且结果也是集合类型,那么直接赋值,如果不是集合类型,则创建空集合对象,其他类型返回null
Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
// 如果该字段是集合类型,那么将当前列的值保存到集合对象中
if (collectionProperty != null) {
MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
targetMetaObject.add(rowValue);
}
// 如果当前列的值不是集合,则直接将值设置到对象中
else {
metaObject.setValue(resultMapping.getProperty(), rowValue);
}
}
/**
* 根据discriminated标签,决定具体应该使用哪一个resultMap,如果不存在discriminator,则直接返回给定的resultMap,如果存在,返回经过映射列合并的resultMap
* 因为在resultMap中discriminator必须在最后的位置书写,也就意味着处理discriminator的时候,其他映射字段已经解析成resultMapping了
* mybatis的处理逻辑是,将discriminator中case的映射关系,加上之前所有解析的标签对应的的映射关系(resultMapping)进行合并成一个新的resultMap
* 最终使用某个一resultMap的时候,会判断resultMap是否存在discriminator,如果存在discriminator则会使用合并映射列之后的新resultMap来替换当前使用的resultMap
* 因为替换之后的那个新的resultMap包含了全部的映射列信息,而原来那个resultMap不包含discriminator中的映射列信息
*/
public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
Set<String> pastDiscriminators = new HashSet<>();
// 获取Discriminator信息
Discriminator discriminator = resultMap.discriminator;
// 如果resultMap中存在分支鉴别器,递归处理,如果没有直接返回原始的resultMap
// 递归处理Discriminator,因为discriminator根据值会指定到具体的resultMap,而resultMap中可能又会有discriminator
while (discriminator != null) {
// 获取Discriminator分支的值
Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
// 根据值来获取到指定的resultMap,保存的时候key: 值 - value: resultMapId
String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
// 如果配置对象中不包含这个resultMap,不处理
if (!configuration.hasResultMap(discriminatedMapId)) {
break;
}
// 获取discriminator对应值的这个resultMap,因为discriminator对应值的这个resultMap,对discriminator所在的那个resultMap进行列映射合并成了新的resultMap
// 所以,如果存在discriminator,就要使用合并后的resultMap,因为合并后的resultMap才包含原resultMap+case中的映射列关系
resultMap = configuration.getResultMap(discriminatedMapId);
// 保存当前处理的这个discriminator
Discriminator lastDiscriminator = discriminator;
// 当前处理的discriminator值对应的resultMap中,是否也有discriminator,如果有,也要处理
discriminator = resultMap.getDiscriminator();
// discriminator值对应的resultMap就是当前本身的resultMap,就不需要处理,直接返回当前resultMap
// 或者discriminator的值对应的resultMap已经被处理过了,因为处理之后就会保存到pastDiscriminators中,重复处理就会添加失败
if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
break;
}
}
// 如果存在嵌套的Discriminator,则返回Discriminator分支的resultMap来做映射,否则原样返回传递来的resultMap
// 因为discriminator对应值的这个resultMap,对discriminator所在的那个resultMap进行列映射合并成了新的resultMap
// 所以,如果存在discriminator,就要使用合并后的resultMap,因为合并后的resultMap才包含原resultMap+case中的映射列关系
return resultMap;
}
// 获取Discriminator分支的值
public Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException {
// 获取结果的映射信息
ResultMapping resultMapping = discriminator.getResultMapping();
// 获取类型处理器
TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
// 使用类型转换器从结果集中,获取指定列(带有前缀)的值
return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
}
// 拼接列前缀,将指定列名拼接列前缀返回
public String prependPrefix(String columnName, String prefix) {
if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {
return columnName;
}
return prefix + columnName;
}
// 是否需要继续处理
public boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) {
// 上下文对象没有设置停止处理结果集,并且处理的结果数量没有达到分页限制
return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
}
// 分页跳到指定的行
public void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
// 如果结果集类型不是TYPE_FORWARD_ONLY,则直接使用absolute定位到某一行
if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
rs.absolute(rowBounds.getOffset());
}
return;
}
// 如果结果集类型是TYPE_FORWARD_ONLY,那就要忽略结果,直到指定的位置
for (int i = 0; i < rowBounds.getOffset(); i++) {
if (!rs.next()) {
break;
}
}
}
// 注意: 校验带有嵌套结果映射的映射语句不能与自定义ResultHandler一起使用
// 使用safeResultHandlerEnabled=false设置绕过此检查
// 或设置resultOrdered=true,映射的时候会按照sql的查询列的顺序进行一一映射
protected void checkResultHandler() {
if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.resultOrdered()) {
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.");
}
}
// 校验分页的边界问题
public 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.");
}
}
// 校验结果集个数,必须存在resultMap
public 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() + "'. 'resultType' or 'resultMap' must be specified when there is no corresponding method.");
}
}
// 获取查询返回结果集中的第一个结果集对象,因为可能存在多个结果集的情况
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
// 获取结果集对象
ResultSet rs = stmt.getResultSet();
// 只有在多结果集的情况下才为null
while (rs == null) {
// 是否存在多结果集
if (stmt.getMoreResults()) {
// 获取结果集
rs = stmt.getResultSet();
} else if (stmt.getUpdateCount() == -1) {
break;
}
}
// 返回获取的结果集对象
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
// 因为getFirstResultSet获取了第一个结果集进行处理,接下来要处理获下一个结果集
private ResultSetWrapper getNextResultSet(Statement stmt) {
try {
// JDBC是否支持多结果集并且存在多结果集
if (stmt.getConnection().getMetaData().supportsMultipleResultSets() && (stmt.getMoreResults() || (stmt.getUpdateCount() != -1))) {
// 获取结果集对象
ResultSet rs = stmt.getResultSet();
// 递归获取结果集
if (rs == null) {
return getNextResultSet(stmt);
}
// 返回包装好的结果集对象
return new ResultSetWrapper(rs, configuration);
}
} catch (Exception e) {
// 出现以,忽略
}
// 如果所有结果集都处理完比,返回null
return null;
}
}
// 延迟加载的映射信息
public static class PendingRelation {
// 结果对象
public MetaObject metaObject;
// 该列的映射信息
public ResultMapping propertyMapping;
}
public static class UnMappedColumnAutoMapping {
// 列名
public String column;
// 属性名
public String property;
// 类型转换器
public TypeHandler<?> typeHandler;
// 是否为简单类型
public boolean primitive;
}
}
// 结果集包装器
public class ResultSetWrapper {
// 结果集对象
public ResultSet resultSet;
// 类型转换器注册表
public TypeHandlerRegistry typeHandlerRegistry;
// 结果集返回的所有列名
public List<String> columnNames = new ArrayList<>();
// 结果集返回的列对应的Java类型
public List<String> classNames = new ArrayList<>();
// 所有列的JDBC类型
public List<JdbcType> jdbcTypes = new ArrayList<>();
// key: 列名
// value: 属性名 -> 类型转换器的映射关系
public Map<String, Map<Class<?>, TypeHandler<?>>> typeHandlerMap = new HashMap<>();
// key: resultMapId+列前缀
// value: 缓存resultMap中的column列名与结果集列名匹配的所有列名(前提是填写了column属性)
public Map<String, List<String>> mappedColumnNamesMap = new HashMap<>();
// key: resultMapId+列前缀
// value: 缓存resultMap中的column列名与结果集列名不能匹配上的所有列名(前提是填写了column属性)
public Map<String, List<String>> unMappedColumnNamesMap = new HashMap<>();
public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.resultSet = rs;
// 获取结果集的元数据
ResultSetMetaData metaData = rs.getMetaData();
// 获取结果集中的所有返回列
int columnCount = metaData.getColumnCount();
// 遍历所有列
for (int i = 1; i <= columnCount; i++) {
// 如果配置中设置了使用列标签获取,则获取列标签,否则获取列名
columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
// 获取该列的JDBC类型
jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
// 获取该列对应的Java类型
classNames.add(metaData.getColumnClassName(i));
}
}
// 获取指定列名的jdbc类型
public JdbcType getJdbcType(String columnName) {
// 遍历所有的列名
for (int i = 0; i < columnNames.size(); i++) {
// 与给定的列名一样(忽略大小写),则返回该列对应的jdbc类型
if (columnNames.get(i).equalsIgnoreCase(columnName)) {
return jdbcTypes.get(i);
}
}
return null;
}
// 获取指定列对应的属性的类型转换器
public TypeHandler<?> getTypeHandler(Class<?> propertyType, String columnName) {
TypeHandler<?> handler = null;
// 获取该列对应的类型转换器Map
Map<Class<?>, TypeHandler<?>> columnHandlers = typeHandlerMap.get(columnName);
// 如果不存在
if (columnHandlers == null) {
// 创建一个空map,标识该列对应的类型转换器Map
columnHandlers = new HashMap<>();
typeHandlerMap.put(columnName, columnHandlers);
} else {
// 如果存在,获取属性对应的类型转换器
handler = columnHandlers.get(propertyType);
}
// 如果该属性不存在类型转换器,这里实际上就是UnkownTypeHandler的逻辑
if (handler == null) {
// 获取该列的JDBC类型
JdbcType jdbcType = getJdbcType(columnName);
// 从类型转换器注册表中,根据属性类型以及JDBC类型获取对应的类型转换器
handler = typeHandlerRegistry.getTypeHandler(propertyType, jdbcType);
// 复制UnknownTypeHandler#resolveTypeHandler的逻辑
// 如果注册表中也不存在该字段类型的转换器,或者该转换器类型为未知类型的转换器
if (handler == null || handler instanceof UnknownTypeHandler) {
// 获取列的索引
int index = columnNames.indexOf(columnName);
// 解析该列的Java类型
Class<?> javaType = resolveClass(classNames.get(index));
// 如果类型解析成功,并且jdbc类型也不为null
if (javaType != null && jdbcType != null) {
// 根据解析的java类型与jdbc再从注册表中获取类型转换器
handler = typeHandlerRegistry.getTypeHandler(javaType, jdbcType);
}
// 如果jdbc类型为空,则根据java类型去注册表中获取类型转换器
else if (javaType != null) {
handler = typeHandlerRegistry.getTypeHandler(javaType);
}
// 如果java类型为空,则根据jdbc类型去注册表中获取类型转换器
else if (jdbcType != null) {
handler = typeHandlerRegistry.getTypeHandler(jdbcType);
}
}
// 如果以上这些情况都没有获取到类型转换器,则使用ObjectTypeHandler
if (handler == null || handler instanceof UnknownTypeHandler) {
handler = new ObjectTypeHandler();
}
// 缓存该列对应的类型转换器,key为属性类型
columnHandlers.put(propertyType, handler);
}
// 返回找到的类型转换器
return handler;
}
// 加载映射和未映射的列名
public void loadMappedAndUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {
// 映射的列名
List<String> mappedColumnNames = new ArrayList<>();
// 未映射的列名
List<String> unmappedColumnNames = new ArrayList<>();
// 将列前缀变大写
String upperColumnPrefix = columnPrefix == null ? null : columnPrefix.toUpperCase(Locale.ENGLISH);
// 处理列前缀,将所有的字段名称拼接上前缀返回
Set<String> mappedColumns = prependPrefixes(resultMap.mappedColumns, upperColumnPrefix);
// 遍历结果集中的所有的列名
// 这里做的事就是看一下哪些结果集返回的列名可以通过resultMap设置的column属性映射上和映射不上
for (String columnName : columnNames) {
// 将列名大写
String upperColumnName = columnName.toUpperCase(Locale.ENGLISH);
// 如果自定义了该列名的属性映射(在resultMap中写该字段的映射),保存映射的列名
if (mappedColumns.contains(upperColumnName)) {
mappedColumnNames.add(upperColumnName);
}
// 如果没有在resultMap中写该字段的映射,保存该字段为未映射的列名
else {
unmappedColumnNames.add(columnName);
}
}
// 获取映射的Key,resultMapId+列前缀
String mapKey = getMapKey(resultMap, columnPrefix);
// 缓存resultMap中的column列名与结果集列名能匹配上的所有列名
mappedColumnNamesMap.put(mapKey, mappedColumnNames);
// 缓存resultMap中的column列名与结果集列名不能匹配上的所有列名
unMappedColumnNamesMap.put(mapKey, unmappedColumnNames);
}
// 获取所有在resultMap中的column列名与结果集列名匹配的所有列名(前提是填写了column属性)
public List<String> getMappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {
// 获取所有在resultMap中的column列名与结果集列名匹配的所有列名的缓存(前提是填写了column属性)
List<String> mappedColumnNames = mappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));
// 如果没有缓存
if (mappedColumnNames == null) {
// 加载所有列,包含写了映射上与没有映射上的列名
// 加载之后会缓存到对应的Map中
this.loadMappedAndUnmappedColumnNames(resultMap, columnPrefix);
// 再次缓存中获取
mappedColumnNames = mappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));
}
return mappedColumnNames;
}
// 获取所有在resultMap中的column列名与结果集列名不匹配的所有列名(前提是填写了column属性)
public List<String> getUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {
// 获取所有在resultMap中的column列名与结果集列名不匹配的所有列名(前提是填写了column属性)缓存
List<String> unMappedColumnNames = unMappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));
// 如果没有缓存
if (unMappedColumnNames == null) {
// 加载所有列,包含写了映射上与没有映射上的列名
// 加载之后会缓存到对应的Map中
this.loadMappedAndUnmappedColumnNames(resultMap, columnPrefix);
// 再次缓存中获取
unMappedColumnNames = unMappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));
}
return unMappedColumnNames;
}
// 获取映射的Key,resultMapId+列前缀
public String getMapKey(ResultMap resultMap, String columnPrefix) {
return resultMap.getId() + ":" + columnPrefix;
}
// 处理列前缀,将所有的字段名称拼接上前缀返回
public Set<String> prependPrefixes(Set<String> columnNames, String prefix) {
if (columnNames == null || columnNames.isEmpty() || prefix == null || prefix.length() == 0) {
return columnNames;
}
Set<String> prefixed = new HashSet<>();
for (String columnName : columnNames) {
prefixed.add(prefix + columnName);
}
return prefixed;
}
}
// 保存所有懒加载的属性的集合
public class ResultLoaderMap {
private final Map<String, LoadPair> loaderMap = new HashMap<>();
public void addLoader(String property, MetaObject metaResultObject, ResultLoader resultLoader) {
// 如果属性存在".",将属性使用"."分割之后取第一个元素,最终将属性名转换为大写
String upperFirst = getUppercaseFirstProperty(property);
// 已经添加了这个属性对应的懒加载信息,重复添加抛出异常
if (!upperFirst.equalsIgnoreCase(property) && loaderMap.containsKey(upperFirst)) {
throw new ExecutorException("Nested lazy loaded result property '" + property + "' for query id '" + resultLoader.mappedStatement.getId() + " already exists in the result map. The leftmost property of all lazy loaded properties must be unique within a result map.");
}
// 保存该属性的懒加载信息
loaderMap.put(upperFirst, new LoadPair(property, metaResultObject, resultLoader));
}
// 获取所有懒加载的属性
public final Map<String, LoadPair> getProperties() {
return new HashMap<>(this.loaderMap);
}
// 获取所有懒加载的属性名称
public Set<String> getPropertyNames() {
return loaderMap.keySet();
}
public int size() {
return loaderMap.size();
}
// 是否存在该懒加载属性的加载器
public boolean hasLoader(String property) {
return loaderMap.containsKey(property.toUpperCase(Locale.ENGLISH));
}
// 加载指定的懒加载属性
public boolean load(String property) throws SQLException {
// 获取懒加载的配置信息
LoadPair pair = loaderMap.remove(property.toUpperCase(Locale.ENGLISH));
// 如果存在
if (pair != null) {
// 开始执行懒加载操作
pair.load();
return true;
}
return false;
}
// 移除懒加载属性
public void remove(String property) {
loaderMap.remove(property.toUpperCase(Locale.ENGLISH));
}
// 加载所有保存到LoaderMap中的属性
public void loadAll() throws SQLException {
// 获取所有的属性名
final Set<String> methodNameSet = loaderMap.keySet();
// 遍历所有的属性名
String[] methodNames = methodNameSet.toArray(new String[methodNameSet.size()]);
for (String methodName : methodNames) {
// 一一将这些懒加载的属性进行加载
load(methodName);
}
}
// 如果属性存在".",将属性使用"."分割之后取第一个元素,最终将属性名转换为大写
private static String getUppercaseFirstProperty(String property) {
String[] parts = property.split("\\.");
return parts[0].toUpperCase(Locale.ENGLISH);
}
// 懒加载对象的属性信息
public static class LoadPair implements Serializable {
// 获取配置类的方法
private static final String FACTORY_METHOD = "getConfiguration";
// 序列化检查对象,如果该对象为空,表示经历过序列化
private final transient Object serializationCheck = new Object();
// 结果对象的元数据
private transient MetaObject metaResultObject;
// 结果加载器,用于加载懒加载属性
private transient ResultLoader resultLoader;
// 日志对象
private transient Log log;
// 获取Configuration对象的工厂类
private Class<?> configurationFactory;
// 懒加载的属性名
private final String property;
// 懒加载的映射语句ID
private String mappedStatement;
// 映射语句的参数对象
private Serializable mappedParameter;
private LoadPair(final String property, MetaObject metaResultObject, ResultLoader resultLoader) {
this.property = property;
this.metaResultObject = metaResultObject;
this.resultLoader = resultLoader;
/* 只有当原始对象可以序列化时才保存所需的信息. */
if (metaResultObject != null && metaResultObject.getOriginalObject() instanceof Serializable) {
final Object mappedStatementParameter = resultLoader.parameterObject;
if (mappedStatementParameter instanceof Serializable) {
this.mappedStatement = resultLoader.mappedStatement.getId();
this.mappedParameter = (Serializable) mappedStatementParameter;
this.configurationFactory = resultLoader.configuration.configurationFactory;
return;
}
Log log = this.getLogger();
if (log.isDebugEnabled()) {
log.debug("Property [" + this.property + "] of [" + metaResultObject.getOriginalObject().getClass() + "] cannot be loaded " + "after deserialization. Make sure it's loaded before serializing " + "forenamed object.");
}
}
}
// 加载属性
public void load() throws SQLException {
if (this.metaResultObject == null) {
throw new IllegalArgumentException("metaResultObject is null");
}
if (this.resultLoader == null) {
throw new IllegalArgumentException("resultLoader is null");
}
// 加载属性
this.load(null);
}
// 自定义的结果对象填充懒加载属性
public void load(final Object userObject) throws SQLException {
// 结果对象的元数据和结果加载器都为空的情况下,表示当前类经历过序列化,我们需要补充序列化丢失的加载相关数据
if (this.metaResultObject == null || this.resultLoader == null) {
// 如果映射语句对应的参数也为空,抛出异常
if (this.mappedParameter == null) {
throw new ExecutorException("Property [" + this.property + "] cannot be loaded because " + "required parameter of mapped statement [" + this.mappedStatement + "] is not serializable.");
}
// 重新生成配置类对象
final Configuration config = this.getConfiguration();
// 从配置类中获取映射语句信息
final MappedStatement ms = config.getMappedStatement(this.mappedStatement);
if (ms == null) {
throw new ExecutorException("Cannot lazy load property [" + this.property + "] of deserialized object [" + userObject.getClass() + "] because configuration does not contain statement [" + this.mappedStatement + "]");
}
// 创建结果对象
this.metaResultObject = config.newMetaObject(userObject);
// 重新创建resultLoader结果加载器
this.resultLoader = new ResultLoader(config, new ClosedExecutor(), ms, this.mappedParameter, metaResultObject.getSetterType(this.property), null, null);
}
// serializationCheck为空表示经过序列化了
// 上面this.metaResultObject == null || this.resultLoader == null已经处理过了序列化丢失的对象,如果到这里有两种情况
// 一种是经历过上面的判断,那么this.resultLoader被重新创建过了,另一种是没经历过上面的判断,那么this.resultLoader肯定不为空
// 由于执行器是线程不安全的,因此让这两种情况的的执行器都要一致,都使用ClosedExecutor,并保证执行器不允许执行任务
if (this.serializationCheck == null) {
final ResultLoader old = this.resultLoader;
// 无论那种情况,执行器都设置为ClosedExecutor
this.resultLoader = new ResultLoader(old.configuration, new ClosedExecutor(), old.mappedStatement, old.parameterObject, old.targetType, old.cacheKey, old.boundSql);
}
// 使用结果加载器加载懒加载的结果,并设置到结果对象中
// 由于在resultLoader加载结果的时候,会判断创建ResultLoader对象的线程与执行loadResult方法的线程是不是同一个线程,如果是,将会使用resultLoader提供的执行器执行SQL
// 而在上面过程中,传递的执行器都是ClosedExecutor,该执行器不可以执行任何CRUD操作,如果执行CRUD操作,将会抛出异常
// 因此,如果当前LoadPair被序列化了,那么加载结果的时候,将会抛出异常
this.metaResultObject.setValue(property, this.resultLoader.loadResult());
}
// 通过Configuration的对象工厂创建Configuration对象,返回的Configuration实例用来加载被反序列化对象的延迟加载属性值
// 这个类必须包含一个static Configuration getConfiguration()的方法
private Configuration getConfiguration() {
if (this.configurationFactory == null) {
throw new ExecutorException("Cannot get Configuration as configuration factory was not set.");
}
final Method factoryMethod = this.configurationFactory.getDeclaredMethod(FACTORY_METHOD);
if (!Modifier.isStatic(factoryMethod.getModifiers())) {
throw new ExecutorException("Cannot get Configuration as factory method [" + this.configurationFactory + "]#[" + FACTORY_METHOD + "] is not static.");
}
return Configuration.class.cast(factoryMethod.invoke(null));
}
private Log getLogger() {
if (this.log == null) {
this.log = LogFactory.getLog(this.getClass());
}
return this.log;
}
}
// 已关闭的执行器对象,该对象不能执行任何CRUD操作,否则抛出异常
private static final class ClosedExecutor extends Executor.BaseExecutor {
public ClosedExecutor() {
super(null, null);
}
@Override
public boolean isClosed() {
return true;
}
@Override
protected int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
throw new UnsupportedOperationException("Not supported.");
}
@Override
protected List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
throw new UnsupportedOperationException("Not supported.");
}
@Override
protected <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
throw new UnsupportedOperationException("Not supported.");
}
@Override
protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
throw new UnsupportedOperationException("Not supported.");
}
}
}
// ResultMap结果集映射对象
public class ResultMap {
// 配置信息
public Configuration configuration;
// resultMap的ID
public String id;
// resultMap最终的结果类型
public Class<?> type;
// 所有的结果字段映射
public List<ResultMapping> resultMappings;
// id类型的参数映射
public List<ResultMapping> idResultMappings;
// 构造函数参数映射
public List<ResultMapping> constructorResultMappings;
// result类型的参数映射
public List<ResultMapping> propertyResultMappings;
// 映射的列名集合
// 在resultMap中字段映射设置的column列名,如果设置了column属性,保存到映射列名的集合中
public Set<String> mappedColumns;
// 映射的属性集合
// 在resultMap中字段映射设置的property属性名,如果设置property属性,保存到映射属性名的集合中
public Set<String> mappedProperties;
// resultMap的分支鉴别器
public Discriminator discriminator;
// 是否有嵌套的resultMap
// 在resultMap标签中,如果具有"association", "collection", "case"其中的一个,那么就是嵌套的resultMap,因为在这些标签内部,也可以填写与resultMap完全一样的映射关系
public boolean hasNestedResultMaps;
// 是否有嵌套的查询
public boolean hasNestedQueries;
// 是否自动映射
public Boolean autoMapping;
public static class Builder {
public ResultMap resultMap = new ResultMap();
public ResultMap build() {
if (resultMap.id == null) {
throw new IllegalArgumentException("ResultMaps must have an id");
}
resultMap.mappedColumns = new HashSet<>();
resultMap.mappedProperties = new HashSet<>();
resultMap.idResultMappings = new ArrayList<>();
resultMap.constructorResultMappings = new ArrayList<>();
resultMap.propertyResultMappings = new ArrayList<>();
List<String> constructorArgNames = new ArrayList<>();
// 遍历所有的字段映射
for (ResultMapping resultMapping : resultMap.resultMappings) {
// 是否存在嵌套查询
resultMap.hasNestedQueries = resultMap.hasNestedQueries || resultMapping.nestedQueryId != null;
// 在resultMap标签中,如果具有"association", "collection", "case"其中的一个,那么就是嵌套的resultMap,因为在这些标签内部,也可以填写与resultMap完全一样的映射关系
resultMap.hasNestedResultMaps = resultMap.hasNestedResultMaps || resultMapping.nestedResultMapId != null && resultMapping.resultSet == null;
// 获取在resultMap中字段映射设置的column列名,如果设置了column属性,保存到映射列名的集合中
// 使用column="{propId=prop_id,name=name}这种格式填写的列名映射,保存到resultMapping.composites中,而不是保存到resultMapping.column
String column = resultMapping.column;
if (column != null) {
// 保存映射的列名
resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH));
}
// 如果没用获取到column属性,可能该字段是复合字段映射column="{propId=prop_id,name=name}这种形式
else if (resultMapping.isCompositeResult()) {
// 遍历所有复合列
for (ResultMapping compositeResultMapping : resultMapping.composites) {
// 添加所有列
String compositeColumn = compositeResultMapping.getColumn();
if (compositeColumn != null) {
resultMap.mappedColumns.add(compositeColumn.toUpperCase(Locale.ENGLISH));
}
}
}
// 获取属性名,在resultMap字段映射中填写了property属性
String property = resultMapping.property;
// 如果在resultMap字段映射中填写了property属性
if (property != null) {
// 保存映射的属性名
resultMap.mappedProperties.add(property);
}
// 获取映射类型,如果为构造映射
if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) {
// 保存将该映射关系保存到到构造映射的集合中
resultMap.constructorResultMappings.add(resultMapping);
// 如果存在属性信息,将属性名保存到构造参数的名称集合中
if (resultMapping.getProperty() != null) {
constructorArgNames.add(resultMapping.getProperty());
}
}
// 如果不是构造参数映射,就是普通的映射,保存到普通属性映射集合中
else {
resultMap.propertyResultMappings.add(resultMapping);
}
// 如果该映射类型是ID映射
if (resultMapping.getFlags().contains(ResultFlag.ID)) {
// 将该映射信息保存到ID映射的集合中
resultMap.idResultMappings.add(resultMapping);
}
}
// 如果不存在ID映射信息,将所有的映射信息作为ID的映射
if (resultMap.idResultMappings.isEmpty()) {
resultMap.idResultMappings.addAll(resultMap.resultMappings);
}
// 如果存在构造映射
if (!constructorArgNames.isEmpty()) {
// 使用参数映射的属性名称匹配结果对象的构造参数名称和类型,匹配上返回这些参数名,否则返回null
List<String> actualArgNames = this.argNamesOfMatchingConstructor(constructorArgNames);
// 没有匹配上,表示没有与指定的映射一样的构造函数
if (actualArgNames == null) {
throw new BuilderException("Error in result map '" + resultMap.id + "'. Failed to find a constructor in '"
+ resultMap.getType().getName() + "' with arg names " + constructorArgNames
+ ". Note that 'javaType' is required when there is no writable property with the same name ('name' is optional, BTW). There might be more info in debug log.");
}
// 对构造参数进行排序
resultMap.constructorResultMappings.sort((o1, o2) -> {
int paramIdx1 = actualArgNames.indexOf(o1.getProperty());
int paramIdx2 = actualArgNames.indexOf(o2.getProperty());
return paramIdx1 - paramIdx2;
});
}
// 将这些集合都变为不可修改的集合
resultMap.resultMappings = Collections.unmodifiableList(resultMap.resultMappings);
resultMap.idResultMappings = Collections.unmodifiableList(resultMap.idResultMappings);
resultMap.constructorResultMappings = Collections.unmodifiableList(resultMap.constructorResultMappings);
resultMap.propertyResultMappings = Collections.unmodifiableList(resultMap.propertyResultMappings);
resultMap.mappedColumns = Collections.unmodifiableSet(resultMap.mappedColumns);
return resultMap;
}
// 强制使用嵌套的resultMap
public void forceNestedResultMaps() {
hasNestedResultMaps = true;
}
// 使用参数映射的属性名称匹配结果对象的构造参数名称和类型,匹配上返回这些参数名,否则返回null
public List<String> argNamesOfMatchingConstructor(List<String> constructorArgNames) {
// 获取结果对象的构造函数
Constructor<?>[] constructors = resultMap.type.getDeclaredConstructors();
// 遍历所有构造函数
for (Constructor<?> constructor : constructors) {
// 获取构造参数类型
Class<?>[] paramTypes = constructor.getParameterTypes();
// 如果该构造函数的参数个数与给定的映射结果写的参数个数一样,则可以使用
if (constructorArgNames.size() == paramTypes.length) {
// 获取构造函数的参数的名称
List<String> paramNames = this.getArgNames(constructor);
// 如果所有参数名都匹配,并且所有的参数类型都匹配,则返回匹配的所有构造参数名称
if (constructorArgNames.containsAll(paramNames) && argTypesMatch(constructorArgNames, paramTypes, paramNames)) {
return paramNames;
}
}
}
return null;
}
// 参数类型匹配,将构造函数参数的类型与映射关系中写的java类型进行一一匹配,全部匹配成功才算通过
public boolean argTypesMatch(List<String> constructorArgNames, Class<?>[] paramTypes, List<String> paramNames) {
// 获取所有参数名称
for (int i = 0; i < constructorArgNames.size(); i++) {
// 获取参数的实际类型
Class<?> actualType = paramTypes[paramNames.indexOf(constructorArgNames.get(i))];
// 获取映射关系中指定的java类型
Class<?> specifiedType = resultMap.constructorResultMappings.get(i).getJavaType();
// 如果不一致,则匹配失败,所有的字段类型都匹配成功才算成功
if (!actualType.equals(specifiedType)) {
if (log.isDebugEnabled()) {
log.debug("While building result map '" + resultMap.id + "', found a constructor with arg names " + constructorArgNames + ", but the type of '" + constructorArgNames.get(i) + "' did not match. Specified: [" + specifiedType.getName() + "] Declared: [" + actualType.getName() + "]");
}
return false;
}
}
return true;
}
// 获取参数的名称
public List<String> getArgNames(Constructor<?> constructor) {
List<String> paramNames = new ArrayList<>();
List<String> actualParamNames = null;
// 获取注解信息
Annotation[][] paramAnnotations = constructor.getParameterAnnotations();
int paramCount = paramAnnotations.length;
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
String name = null;
// 如果存在@Param注解,取注解中的名称
for (Annotation annotation : paramAnnotations[paramIndex]) {
if (annotation instanceof Param) {
name = ((Param) annotation).value();
break;
}
}
// 如果不存在注解,配置中设置了使用真实的参数名称,直接使用参数写的参数名称
if (name == null && resultMap.configuration.isUseActualParamName()) {
if (actualParamNames == null) {
actualParamNames = ParamNameUtil.getParamNames(constructor);
}
if (actualParamNames.size() > paramIndex) {
name = actualParamNames.get(paramIndex);
}
}
// 如果以上两种情况都没满足,则固定使用"arg+参数下标"作为参数名称
paramNames.add(name != null ? name : "arg" + paramIndex);
}
return paramNames;
}
}
}
// 用于加载的结果加载器
public class ResultLoader {
// 配置信息
protected final Configuration configuration;
// 执行器
protected final Executor executor;
// 加载的映射语句
protected final MappedStatement mappedStatement;
// 加载映射语句的参数对象
protected final Object parameterObject;
// 加载对象的结果类型
protected final Class<?> targetType;
// 反射创建对象的工厂
protected final ObjectFactory objectFactory;
// 加载映射语句的缓存Key
protected final CacheKey cacheKey;
// 加载的SQL绑定信息
protected final BoundSql boundSql;
// 结果提取器,就是根据查询处理的结果转换成目标接口的返回值(例如,都是通过selectList查询,最终需要返回单个对象,或者Map等等)
protected final ResultExtractor resultExtractor;
// 创建当前ResultLoader的线程ID
protected final long creatorThreadId = Thread.currentThread().getId();
// 是否已经加载过
protected boolean loaded;
// 最终加载的结果对象
protected Object resultObject;
public ResultLoader(Configuration config, Executor executor, MappedStatement mappedStatement, Object parameterObject, Class<?> targetType, CacheKey cacheKey, BoundSql boundSql) {
this.configuration = config;
this.executor = executor;
this.mappedStatement = mappedStatement;
this.parameterObject = parameterObject;
this.targetType = targetType;
this.objectFactory = configuration.getObjectFactory();
this.cacheKey = cacheKey;
this.boundSql = boundSql;
this.resultExtractor = new ResultExtractor(configuration, objectFactory);
this.creatorThreadId = Thread.currentThread().getId();
}
// 加载结果
public Object loadResult() throws SQLException {
List<Object> list = this.selectList();
resultObject = resultExtractor.extractObjectFromList(list, targetType);
return resultObject;
}
// 查询数据
private <E> List<E> selectList() throws SQLException {
Executor localExecutor = executor;
// 如果进行查询的线程不是创建ResultLoader时的那个线程,说白了就是判断懒加载的时机
// 如果线程相同,就使用创建时的那个执行器执行查询操作,如果不同线程,就创建一个简单类型的执行器执行SQL
if (Thread.currentThread().getId() != this.creatorThreadId || localExecutor.isClosed()) {
// 如果不是,那么创建一个新的执行器,专门用于
localExecutor = newExecutor();
}
// 执行查询操作
List<E> list = localExecutor.query(mappedStatement, parameterObject, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, cacheKey, boundSql);
// 如果创建了新的执行器,将执行器关闭
if (localExecutor != executor) {
localExecutor.close(false);
}
// 返回结果
return list;
}
// 创建新的执行器用于执行懒加载的映射语句
private Executor newExecutor() {
// 获取环境对象
final Environment environment = configuration.getEnvironment();
if (environment == null) {
throw new ExecutorException("ResultLoader could not load lazily. Environment was not configured.");
}
// 获取数据源
final DataSource ds = environment.getDataSource();
if (ds == null) {
throw new ExecutorException("ResultLoader could not load lazily. DataSource was not configured.");
}
// 获取事务工厂
final TransactionFactory transactionFactory = environment.getTransactionFactory();
// 创建事务
final Transaction tx = transactionFactory.newTransaction(ds, null, false);
// 创建一个新的执行器实例
return configuration.newExecutor(tx, ExecutorType.SIMPLE);
}
// 结果是否为空
public boolean wasNull() {
return resultObject == null;
}
}
// 核心配置类组件
public class Configuration {
// Mybatis的环境对象
public Environment environment;
// 是否允许在嵌套语句中使用分页(RowBounds),false为允许(默认),true:不允许
public boolean safeRowBoundsEnabled;
// 是否允许在嵌套语句中使用自定义结果处理器(ResultHandler),false:为允许,true:不允许(默认)
public boolean safeResultHandlerEnabled = true;
// 映射字段将下划线转驼峰
public boolean mapUnderscoreToCamelCase;
// 用于控制懒加载的行为,开启时,任一方法的调用都会加载该对象的所有延迟加载属性,否则,每个延迟加载属性会按需加载
public boolean aggressiveLazyLoading;
// 是否允许单个语句返回多结果集(需要数据库驱动支持)
public boolean multipleResultSetsEnabled = true;
// 允许JDBC支持自动生成主键,需要数据库驱动支持,true:强制使用自动生成主键
public boolean useGeneratedKeys;
// 使用列标签代替列名,实际表现依赖于数据库驱动
public boolean useColumnLabel = true;
// 开启二级缓存(默认开启)
public boolean cacheEnabled = true;
// 当结果集中的字段值为null的情况下,是否要调用结果对象的setter/map.put方法
public boolean callSettersOnNulls;
// 使用方法填写的实际名称作为SQL语句的参数名称,为了使用该特性,项目必须采用Java8编译,并且加上 `-parameters` 选项
public boolean useActualParamName = true;
// 当返回行的所有列都是空时,是否直接返回null,这个配置开启会返回一个空实例,它也适用于嵌套的结果集(如集合或关联)
// 默认为false,直接返回null
public boolean returnInstanceForEmptyRow;
// 从SQL中删除多余的空格字符,请注意,这也会影响SQL中的文字字符串
public boolean shrinkWhitespacesInSql;
// 为 'foreach' 标签的 'nullable' 属性指定默认值
public boolean nullableOnForEach;
// 构造参数使用参数名称进行映射,而不需要指定resultMap参数映射
public boolean argNameBasedConstructorAutoMapping;
// 指定MyBatis增加到日志名称的前缀
public String logPrefix;
// 指定MyBatis所用日志的具体实现,未指定时将自动查找。
public Class<? extends Log> logImpl;
// 指定 VFS 的实现
public Class<? extends VFS> vfsImpl;
// 指定一个提供接口SQL的provider类,这个类适用于指定@SqlProvider注解上的`type`(或`value`)属性,例如: 在@SelectProvider注解中使用构造SQL语句的默认的类
public Class<?> defaultSqlProviderType;
// MyBatis利用本地缓存机制(LocalCache)防止循环引用和加速重复的嵌套查询
// 默认值为SESSION,会缓存一个会话(SqlSession)中执行的所有查询
// 若设置值为STATEMENT,本地缓存将仅用于执行当前这条SQL需要处理的数据,对相同SqlSession的不同查询将不会进行缓存
public LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
// 空值null的默认JDBC类型
public JdbcType jdbcTypeForNull = JdbcType.OTHER;
// 指定对象的哪些方法触发一次延迟加载
public Set<String> lazyLoadTriggerMethods = new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString"));
// 设置超时时间,它决定数据库驱动等待数据库响应的秒数。
public Integer defaultStatementTimeout;
// 为驱动的结果集获取数量(fetchSize)设置一个建议值,此参数只可以在查询设置中被覆盖
public Integer defaultFetchSize;
// 指定映射语句的结果集类型
public ResultSetType defaultResultSetType;
// 配置默认的执行器
// SIMPLE 就是普通的执行器;
// REUSE 执行器会重用预处理语句(PreparedStatement)
// BATCH 执行器不仅重用语句还会执行批量更新。
public ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
// 指定MyBatis应如何自动映射列到字段或属性
// NONE 表示关闭自动映射;
// PARTIAL 只会自动映射没有定义嵌套结果映射的字段。
// FULL 会自动映射任何复杂的结果集(无论是否嵌套)
public AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
// 无法进行映射的列的默认行为
// 例如结果集字段没有,但是在resultMap设置了,或者resultMap没有设置,结果集字段有
public AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
// 当前配置类公用的属性信息
public Properties variables = new Properties();
// 创建Reflector的工厂,Reflector可以获取类的反射信息
public ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
// 每次MyBatis创建结果对象的新实例时,都会使用(ObjectFactory)实例来完成实例化工作
public ObjectFactory objectFactory = new DefaultObjectFactory();
// ObjectWrapperFactory用于创建ObjectWrapper的工厂
// 对象包装器(ObjectWrapper)用于处理从数据库中获取的数据对象,并提供对这些对象属性的访问和修改方法。
public ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
// 延迟加载的全局开关,当开启时,所有关联对象都会延迟加载,特定关联关系中可通过设置 `fetchType` 属性来覆盖该项的开关状态
public boolean lazyLoadingEnabled;
// 用于创建动态代理对象的工厂,MyBatis中,动态代理被广泛用于生成接口的实现类,以便实现延迟加载、拦截器等功能
public ProxyFactory proxyFactory = new JavassistProxyFactory();
// 数据库ID,使用的数据库类型的唯一标识
public String databaseId;
// 指定一个提供Configuration实例的类,返回的Configuration实例用来加载被反序列化对象的延迟加载属性值
// 这个类必须包含一个static Configuration getConfiguration()的方法
public Class<?> configurationFactory;
// Mapper的注册表
public MapperRegistry mapperRegistry = new MapperRegistry(this);
// 拦截器的执行链
public InterceptorChain interceptorChain = new InterceptorChain();
// 类型转换器的注册表
public TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);
// 类型别名的注册表
public TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
// mapper.xml文件模板的语言驱动的注册表
public LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
// 每一个MappedStatement它代表了一个映射的SQL语句
public Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection").conflictMessageProducer((savedValue, targetValue) -> ". please check " + savedValue.getResource() + " and " + targetValue.getResource());
// 所有的Mapper缓存(二级缓存对象)
public Map<String, Cache> caches = new StrictMap<>("Caches collection");
// 所有的ResultMap
// xml中所有的<resultMap>
public Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
// 所有的ParameterMap
// xml中所有的<parameterMap>
public Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
// 所有的生成Insert的Id的KeyGenerator
public Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");
// 已经加载过的的资源文件
public Set<String> loadedResources = new HashSet<>();
// 所有的SQL片段
// xml中所有的<sql>
public Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");
// 例如:在mapper.xm中配置了<cache-ref xxx="xxx"/>需要引用某个缓存,但是引用的这个缓存的命名空间还没有被解析,此时该mapper.xml暂时就无法解析成功,就会保存起来
// 未解析成功的Mapper.xml的解析器对象之后会再重新解析
public Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<>();
/**
* 和{@link Configuration#incompleteStatements}一样,只是incompleteStatements的级别是mapper.xml级别,而incompleteCacheRefs是<cache-ref/>级别
* 当某个mapper.xml使用<cache-ref/>引用了另一个mapper的缓存,而那个mapper的缓存并没有被加载,这种情况下,这mapper的缓存引用关系需要记录下来,后面再进行解析
*/
public Collection<Resolver.CacheRefResolver> incompleteCacheRefs = new LinkedList<>();
// 在mapper.xml中,resultMap中存在可能存在继承关系,当解析某一个resultMap的时候,它继承的resultMap还未被解析,这种情况需要被记录下来
// 等继承的resultMap被解析完成的时候,该resultMap又会继续解析
public Collection<Resolver.ResultMapResolver> incompleteResultMaps = new LinkedList<>();
/**
* 和{@link Configuration#incompleteStatements}完全一样,但是它是基于方法注解@CacheNamespaceRef的情况下产生的缓存引用
*/
public Collection<Resolver.MethodResolver> incompleteMethods = new LinkedList<>();
// 缓存的引用关系Map集合,key: Mapper的namespace,value: 引用的缓存的mapper的namespace
public Map<String, String> cacheRefMap = new HashMap<>();
public Configuration(Environment environment) {
this();
this.environment = environment;
}
// 注册默认的别名信息
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}
public void setLogImpl(Class<? extends Log> logImpl) {
if (logImpl != null) {
this.logImpl = logImpl;
LogFactory.useCustomLogging(this.logImpl);
}
}
public void setVfsImpl(Class<? extends VFS> vfsImpl) {
if (vfsImpl != null) {
this.vfsImpl = vfsImpl;
VFS.addImplClass(this.vfsImpl);
}
}
public void setProxyFactory(ProxyFactory proxyFactory) {
if (proxyFactory == null) {
proxyFactory = new JavassistProxyFactory();
}
this.proxyFactory = proxyFactory;
}
public void setDefaultEnumTypeHandler(Class<? extends TypeHandler> typeHandler) {
if (typeHandler != null) {
typeHandlerRegistry.setDefaultEnumTypeHandler(typeHandler);
}
}
public List<Interceptor> getInterceptors() {
return interceptorChain.getInterceptors();
}
public void setDefaultScriptingLanguage(Class<? extends LanguageDriver> driver) {
if (driver == null) {
driver = LanguageDriver.XMLLanguageDriver.class;
}
languageRegistry.setDefaultDriverClass(driver);
}
public LanguageDriver getDefaultScriptingLanguageInstance() {
return languageRegistry.getDefaultDriver();
}
public LanguageDriver getLanguageDriver(Class<? extends LanguageDriver> langClass) {
if (langClass == null) {
// 默认为: XMLLanguageDriver
return languageRegistry.getDefaultDriver();
}
languageRegistry.register(langClass);
return languageRegistry.getDriver(langClass);
}
// 将指定对象封装成可以动态多层级的操作属性和方法的类
public MetaObject newMetaObject(Object object) {
return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}
// 创建Parameter参数处理器
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
// 执行所有拦截器
return (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
}
// 创建ResultSet结果集处理器
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new ResultSetHandler.DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
// 执行所有拦截器
return (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
}
// 创建Statement处理器
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 执行所有拦截器
return (StatementHandler) interceptorChain.pluginAll(statementHandler);
}
// 创建默认的执行器
public Executor newExecutor(Transaction transaction) {
return newExecutor(transaction, defaultExecutorType);
}
// 创建指定类型的执行器
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new Executor.BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new Executor.ReuseExecutor(this, transaction);
} else {
executor = new Executor.SimpleExecutor(this, transaction);
}
// 如果开启了二级缓存,使用了装饰器模式
if (cacheEnabled) {
executor = new Executor.CachingExecutor(executor);
}
// 执行所有拦截器
return (Executor) interceptorChain.pluginAll(executor);
}
// 保存缓存信息
public void addCache(Cache cache) {
caches.put(cache.getId(), cache);
}
// 保存ResultMap
public void addResultMap(ResultMap rm) {
resultMaps.put(rm.getId(), rm);
// 校验Discriminated和Result的关系
this.checkLocalfinallyForDiscriminatedNestedResultMaps(rm);
this.checkGlobalfinallyForDiscriminatedNestedResultMaps(rm);
}
// 保存MappedStatement
public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms);
}
// 获取所有映射语句的Id
public Collection<String> getMappedStatementNames() {
// 将未完成的属性重新构建一次
this.buildAllStatements();
// 返回所有的映射语句的Id
return mappedStatements.keySet();
}
// 获取所有的映射语句
public Collection<MappedStatement> getMappedStatements() {
// 将未完成的属性重新构建一次
this.buildAllStatements();
// 返回所有的映射语句
return mappedStatements.values();
}
// 返回指定的映射语句
public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
// 是否需要验证存在未完成解析的数据,例如resultMapA 继承 resultMapB,解析resultMapA的时候,B还没有被解析,此时resultMapA会挂起,后面在来处理
if (validateIncompleteStatements) {
// 将未完成的属性重新构建一次
this.buildAllStatements();
}
// 返回指定的映射语句
return mappedStatements.get(id);
}
public void addInterceptor(Interceptor interceptor) {
interceptorChain.addInterceptor(interceptor);
}
// 添加整个包的mapper指定类型的mapper接口
public void addMappers(String packageName, Class<?> superType) {
mapperRegistry.addMappers(packageName, superType);
}
// 添加整个包的mapper接口
public void addMappers(String packageName) {
mapperRegistry.addMappers(packageName);
}
// 添加单个mapper接口
public <T> void addMapper(Class<T> type) {
mapperRegistry.addMapper(type);
}
// 获取mapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
// 是否存在指定的映射语句
public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {
// 是否需要验证存在未完成解析的数据,例如resultMapA 继承 resultMapB,解析resultMapA的时候,B还没有被解析,此时resultMapA会挂起,后面在来处理
if (validateIncompleteStatements) {
// 将未完成的属性重新构建一次
this.buildAllStatements();
}
// 当前保存的所有映射语句中是否包含该映射语句
return mappedStatements.containsKey(statementName);
}
public void addCacheRef(String namespace, String referencedNamespace) {
cacheRefMap.put(namespace, referencedNamespace);
}
// 构建所有的statement(sql语句),因为可能在之前解析的时候抛出异常了,保存到这些未完成的属性集合中,现在再解析之前未解析完成的属性
public void buildAllStatements() {
// 解析之前未解析完成的ResultMap,因为resultMap存在继承关系,当继承的reusltMap还没被加载的时候,正在解析的这个resultMap就会被挂起
this.parsePendingResultMaps();
// 如果存在未解析缓存引用
if (!incompleteCacheRefs.isEmpty()) {
synchronized (incompleteCacheRefs) {
// 解析缓存引用
incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null);
}
}
// 如果该映射语句设置了需要引用某个缓存,但是它还未被解析完成,它会被挂起
if (!incompleteStatements.isEmpty()) {
synchronized (incompleteStatements) {
// 解析crud的sql标签
incompleteStatements.removeIf(x -> {
x.parseStatementNode();
return true;
});
}
}
// 处理未解析完成的方法的解析器,该解析器是在加载Mapper接口方法的时候,该方法标注的注解需要使用的的缓存还没加载的情况
if (!incompleteMethods.isEmpty()) {
synchronized (incompleteMethods) {
// 解析该方法对象
incompleteMethods.removeIf(x -> {
x.resolve();
return true;
});
}
}
}
// 解析之前未解析完成的ResultMap,因为resultMap存在继承关系,当继承的reusltMap还没被加载的时候,正在解析的这个resultMap就会被挂起
public void parsePendingResultMaps() {
// 用于存储未完成的结果映射解析器
// 在MyBatis中,结果映射用于定义查询结果与 Java 对象之间的映射关系,这个集合存储了尚未完成解析的结果映射对象。
if (incompleteResultMaps.isEmpty()) {
return;
}
synchronized (incompleteResultMaps) {
boolean resolved;
IncompleteElementException ex = null;
do {
resolved = false;
// 获取到未解析完成的的resultMap
Iterator<Resolver.ResultMapResolver> iterator = incompleteResultMaps.iterator();
while (iterator.hasNext()) {
try {
// 解析该ResultMap
Resolver.ResultMapResolver resolver = iterator.next();
resolver.resolve();
iterator.remove();
// 标记该resultMap被解析了
resolved = true;
} catch (IncompleteElementException e) {
ex = e;
}
}
} while (resolved);
if (!incompleteResultMaps.isEmpty() && ex != null) {
// 至少有一个结果映射无法解析
throw ex;
}
}
}
// 保存已经解析过的资源
public void addLoadedResource(String resource) {
loadedResources.add(resource);
}
// 该资源是否被解析过
public boolean isResourceLoaded(String resource) {
return loadedResources.contains(resource);
}
// 自定义严格的Map
public static class StrictMap<V> extends ConcurrentHashMap<String, V> {
// map的名称
public String name;
// 冲突的异常提示消息生成器
public BiFunction<V, V, String> conflictMessageProducer;
@Override
public V put(String key, V value) {
// 已经存在该Key(排除key为null的情况),抛出异常
if (containsKey(key)) {
throw new IllegalArgumentException(name + " already contains value for " + key + (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
}
// 如果包含"."
if (key.contains(".")) {
// 获取最后一个点之后的名称
String shortKey = getShortName(key);
// 如果之前不存在该元素,则保存该值
if (super.get(shortKey) == null) {
super.put(shortKey, value);
} else {
// 如果之前就已经存在该值,使用Ambiguity(不清晰的标记)覆盖之前的值
// 用于后续获取抛出异常的标记
super.put(shortKey, (V) new Ambiguity(shortKey));
}
}
// 如果不存在".",直接保存
return super.put(key, value);
}
@Override
public 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;
}
// 模棱两可的值标记
public static class Ambiguity {
public String subject;
public Ambiguity(String subject) {
this.subject = subject;
}
public String getSubject() {
return subject;
}
}
}
}
// 结果的字段信息信息
public class ResultMapping {
// 配置信息
public Configuration configuration;
// 属性名
public String property;
// 列名
public String column;
// java类型
public Class<?> javaType;
// jdbc类型
public JdbcType jdbcType;
/// 类型转换器
public TypeHandler<?> typeHandler;
// 嵌套的resultMap
public String nestedResultMapId;
// 嵌套的查询Id
public String nestedQueryId;
// 不为空的列名
public Set<String> notNullColumns;
// 列名前缀
public String columnPrefix;
// 映射结果的类型(构造函数,ID)
public List<ResultFlag> flags;
/**
* 复合列的映射信息,存在多个列的映射
* <pre>
* <resultMap id="userResultMap" type="User">
* <association property="author" javaType="Author"
* select="selectByIdAndName" column="{propId=prop_id,name=name}" >
* </resultMap>
* </pre>
*/
public List<ResultMapping> composites;
// 指定用于加载复杂类型的结果集名字
public String resultSet;
// 指定关联的外键的列名
public String foreignColumn;
// 是否懒加载
public boolean lazy;
public boolean isCompositeResult() {
return this.composites != null && !this.composites.isEmpty();
}
public boolean isSimple() {
return this.nestedResultMapId == null && this.nestedQueryId == null && this.resultSet == null;
}
}
public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;
// 执行增删改
int update(MappedStatement ms, Object parameter) throws SQLException;
// 查询
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
// 游标查询
<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
// 刷新Statements的缓存
List<BatchResult> flushStatements() throws SQLException;
// 提交事务
void commit(boolean required) throws SQLException;
// 回滚事务
void rollback(boolean required) throws SQLException;
// 创建缓存Key
CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
// 是否被缓存了数据
boolean isCached(MappedStatement ms, CacheKey key);
// 清空本地缓存,也就是一级缓存
void clearLocalCache();
// 延迟加载查询
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
// 获取事务
Transaction getTransaction();
// 关闭执行器
void close(boolean forceRollback);
// 执行器是否关闭
boolean isClosed();
// 包装Executor
void setExecutorWrapper(Executor executor);
// 基础的执行器,封装了一些模板方法,通用操作
public abstract class BaseExecutor implements Executor {
// 事务对象
public Transaction transaction;
// 包装的执行器
public Executor wrapper;
// 延迟加载队列
public ConcurrentLinkedQueue<DeferredLoad> deferredLoads;
// 一级缓存
public PerpetualCache localCache;
// 参数缓存,存储过程使用
public PerpetualCache localOutputParameterCache;
// 配置信息
public Configuration configuration;
// 查询的深度,嵌套查询的层次
public int queryStack;
// 当前执行器是否关闭
public boolean closed;
// 获取事务
@Override
public Transaction getTransaction() {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
return transaction;
}
// 关闭执行器
@Override
public void close(boolean forceRollback) {
// 回滚操作,forceRollback: 强制回滚事务
this.rollback(forceRollback);
// 如果存在事务,关闭事务
if (transaction != null) {
transaction.close();
}
// 重置属性
transaction = null;
deferredLoads = null;
localCache = null;
localOutputParameterCache = null;
closed = true;
}
@Override
public boolean isClosed() {
return closed;
}
// 更新操作,insert,delete,update
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 清空一级缓存
clearLocalCache();
// 执行具体的更新操作
return doUpdate(ms, parameter);
}
// 清空statement的缓存
@Override
public List<BatchResult> flushStatements() throws SQLException {
return flushStatements(false);
}
// 刷新statement的缓存
public List<BatchResult> flushStatements(boolean isRollBack) throws SQLException {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 实际完成刷新操作,可能是删除缓存,可能是执行缓存的批量操作,再删除缓存的statement
return doFlushStatements(isRollBack);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 获取SQL的绑定信息
BoundSql boundSql = ms.getBoundSql(parameter);
// 创建缓存Key
CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
// 开始查询
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 第一次执行或者嵌套查询执行完毕才会清空缓存,并且这个SQL需要刷缓存
// 如果没有执行完毕就清空缓存,那么循环依赖触发的嵌套子查询就无法赋值
// 所以,必须所有的子查询执行完毕之后才能清空缓存
if (queryStack == 0 && ms.flushCacheRequired) {
// 清空一级缓存
clearLocalCache();
}
List<E> list;
// 开始第一次查询,记录查询深度
queryStack++;
// 如果存在结果处理器,就不会使用缓存,否则先从缓存中获取数据
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
// 如果缓存中存在数据
if (list != null) {
// 处理存储过程中缓存的参数
handleLocalfinallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 如果缓存中不存在数据,从数据库加载数据,然后放入缓存一级缓存
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
// 执行完成,层次-1
queryStack--;
// 如果执行完成,包括嵌套查询都执行完毕
// 如果没有执行完毕就清空缓存,那么循环依赖触发的嵌套子查询就无法赋值
// 所以,必须所有的子查询执行完毕之后才能清空缓存
if (queryStack == 0) {
// 当前执行的SQL是否存在需要延迟加载的属性,因为当存在循环依赖等操作,会就值缓存起来,然后设置为延迟加载
for (DeferredLoad deferredLoad : deferredLoads) {
// 执行所有的延迟加载,从缓存中获取值,然后处理还没有设置的属性值
deferredLoad.load();
}
// 清空所有的延迟加载属性
deferredLoads.clear();
// 如果缓存的作用于为STATEMENT
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// 清空缓存,该缓存只在Statement(SQL)级别失效
clearLocalCache();
}
}
return list;
}
@Override
public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {
// 获取SQL的绑定信息
BoundSql boundSql = ms.getBoundSql(parameter);
// 执行具体的查询操作
return doQueryCursor(ms, parameter, rowBounds, boundSql);
}
// 延迟加载
@Override
public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 创建延迟加载对象,在resultObject中的property属性暂时没有办法赋值,可能出现了循环依赖
DeferredLoad deferredLoad = new DeferredLoad(resultObject, property, key, localCache, configuration, targetType);
// 是否可以加载,如果缓存中存在值,表示可以加载,就不需要延迟加载
if (deferredLoad.canLoad()) {
// 立即加载,从缓存中获取该属性的值,设置到resultObject中
deferredLoad.load();
} else {
// 无法加载,需要延迟加载的对象数据保存到队列中
deferredLoads.add(new DeferredLoad(resultObject, property, key, localCache, configuration, targetType));
}
}
//
/**
* 生成缓存Key,由以下几部分构成
* 1. statementId
* 2. 分页参数(offset,limit)
* 3. sql
* 4. 参数值
* 5. 环境对象的Id
*/
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 缓存key由一下几部分组成
CacheKey cacheKey = new CacheKey();
// statementId
cacheKey.update(ms.getId());
// 分页条件
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
// SQL
cacheKey.update(boundSql.getSql());
// 获取参数映射
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// 获取类型转换器注册表
TypeHandlerRegistry typeHandlerRegistry = ms.configuration.typeHandlerRegistry;
// 遍历所有的参数映射
for (ParameterMapping parameterMapping : parameterMappings) {
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
// 获取属性名
String propertyName = parameterMapping.getProperty();
// boundSql中的额外设置属性是否存在该属性名
if (boundSql.hasAdditionalParameter(propertyName)) {
// 获取该属性的值
value = boundSql.getAdditionalParameter(propertyName);
}
// 参数对象是否为null
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);
}
}
// 如果存在环境对象
if (configuration.getEnvironment() != null) {
// 环境对象的Id也作为缓存的标识
cacheKey.update(configuration.getEnvironment().getId());
}
return cacheKey;
}
// 当前Key是否被缓存了
@Override
public boolean isCached(MappedStatement ms, CacheKey key) {
return localCache.getObject(key) != null;
}
@Override
public void commit(boolean required) throws SQLException {
if (closed) {
throw new ExecutorException("Cannot commit, transaction is already closed");
}
// 清空一级缓存
this.clearLocalCache();
// 刷新Statements的缓存
this.flushStatements();
// 如果必须提交,则提交事务
if (required) {
transaction.commit();
}
}
// 回滚
@Override
public void rollback(boolean required) throws SQLException {
if (!closed) {
// 清空一级缓存
clearLocalCache();
// 刷新Statements的缓存
flushStatements(true);
// 如果必须回滚,则回滚事务
if (required) {
transaction.rollback();
}
}
}
// 情况一级缓存
@Override
public void clearLocalCache() {
if (!closed) {
// 情况一级缓存
localCache.clear();
// 情况参数缓存
localOutputParameterCache.clear();
}
}
// 关闭statement
public void closeStatement(Statement statement) {
if (statement != null) {
statement.close();
}
}
// 应用事务超时
public void applyTransactionTimeout(Statement statement) throws SQLException {
StatementUtil.applyTransactionTimeout(statement, statement.getQueryTimeout(), transaction.getTimeout());
}
// 处理存储过程中缓存的参数
public void handleLocalfinallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) {
if (ms.getStatementType() == StatementType.CALLABLE) {
Object cachedParameter = localOutputParameterCache.getObject(key);
if (cachedParameter != null && parameter != null) {
MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter);
MetaObject metaParameter = configuration.newMetaObject(parameter);
for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
if (parameterMapping.getMode() != ParameterMode.IN) {
String parameterName = parameterMapping.getProperty();
Object cachedValue = metaCachedParameter.getValue(parameterName);
metaParameter.setValue(parameterName, cachedValue);
}
}
}
}
}
// 从数据库中查询数据
public <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);
// 具体的查询操作
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
// 删除缓存的固定标识
localCache.removeObject(key);
// 将查询的结果进行缓存
localCache.putObject(key, list);
// 如果是存储过程
if (ms.getStatementType() == StatementType.CALLABLE) {
// 将参数缓存
localOutputParameterCache.putObject(key, parameter);
}
// 返回结果
return list;
}
// 获取连接
public Connection getConnection(Log statementLog) throws SQLException {
Connection connection = transaction.getConnection();
if (statementLog.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
}
return connection;
}
@Override
public void setExecutorWrapper(Executor wrapper) {
this.wrapper = wrapper;
}
// 执行更新操作
public abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;
// 实际完成刷新操作,可能是删除缓存,可能是执行缓存的批量操作,再删除缓存的statement
public abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException;
// 查询操作
public abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
// 游标查询
public abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException;
// 延迟加载类,只从缓存中获取数据进行设置
public static class DeferredLoad {
// 结果对象
public MetaObject resultObject;
// 属性名称
public String property;
// 目标类型
public Class<?> targetType;
// 缓存的Key
public CacheKey key;
// 一级缓存
public PerpetualCache localCache;
// 对象工厂
public ObjectFactory objectFactory;
// 结果提取器
public ResultExtractor resultExtractor;
// 是否可以加载,如果缓存中存在值,表示可以加载,就不需要延迟加载
public boolean canLoad() {
return localCache.getObject(key) != null && localCache.getObject(key) != EXECUTION_PLACEHOLDER;
}
// 从缓存中加载数据,处理对象中的循环依赖
public void load() {
// 从缓存中获取数据
List<Object> list = (List<Object>) localCache.getObject(key);
// 使用工具类将list转换为指定类型的数据
Object value = resultExtractor.extractObjectFromList(list, targetType);
// 将转换后的结果设置到结果对象中
resultObject.setValue(property, value);
}
}
}
// 简单的执行器
public class SimpleExecutor extends BaseExecutor {
public SimpleExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
}
// 更新操作
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
// 获取配置类信息
Configuration configuration = ms.getConfiguration();
// 创建Statement处理器,并执行插件,用来处理Statement
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 处理Statement,编译SQL,设置参数
stmt = prepareStatement(handler, ms.getStatementLog());
// 执行statement的更新操作
int update = handler.update(stmt);
closeStatement(stmt);
return update;
}
// 查询操作
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
// 获取配置信息
Configuration configuration = ms.getConfiguration();
// 创建Statement处理器,并执行插件,用来处理Statement
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 处理Statement,编译SQL,设置参数等等
stmt = prepareStatement(handler, ms.getStatementLog());
// 执行statement处理器的查询操作
List<E> list = handler.query(stmt, resultHandler);
closeStatement(stmt);
return list;
}
@Override
protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
// 获取配置信息
Configuration configuration = ms.getConfiguration();
// 创建Statement处理器,并执行插件,用来处理Statement
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
// 处理Statement,编译SQL,设置参数等等
Statement stmt = prepareStatement(handler, ms.getStatementLog());
// 执行statement的游标查询操作
Cursor<E> cursor = handler.queryCursor(stmt);
// 关闭statement
stmt.closeOnCompletion();
return cursor;
}
// 默认无需刷新缓存,只要在statement编译的SQL会重用或者缓存的时候才有必要刷新
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) {
return Collections.emptyList();
}
// 处理Statement,编译SQL,设置参数
public Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 获取连接
Connection connection = this.getConnection(statementLog);
// 处理statement
stmt = handler.prepare(connection, transaction.getTimeout());
// 设置参数
handler.parameterize(stmt);
return stmt;
}
}
// 可复用的执行器
public class ReuseExecutor extends BaseExecutor {
// statement的缓存,key为sql,value为编译sql之后返回的statement对象
public Map<String, Statement> statementMap = new HashMap<>();
// 更新操作
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
// 获取配置信息
Configuration configuration = ms.getConfiguration();
// 创建Statement处理器,并执行插件,用来处理Statement
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 处理statement,编译sql,缓存相同sql的statement,并且设置参数
Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
// 使用Statement执行更新操作
return handler.update(stmt);
}
// 查询操作
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
// 获取配置信息
Configuration configuration = ms.getConfiguration();
// 创建Statement处理器,并执行插件,用来处理Statement
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 处理statement,编译sql,缓存相同sql的statement,并且设置参数
Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
// 使用Statement执行查询操作
return handler.query(stmt, resultHandler);
}
// 游标查询操作
@Override
protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
// 获取配置信息
Configuration configuration = ms.getConfiguration();
// 创建Statement处理器,并执行插件,用来处理Statement
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
// 处理statement,编译sql,缓存相同sql的statement,并且设置参数
Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
// 执行statement处理器的游标查询操作
return handler.queryCursor(stmt);
}
// 刷新所有缓存的statement
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) {
// 关闭所有缓存的statement
for (Statement stmt : statementMap.values()) {
closeStatement(stmt);
}
// 清空缓存的statement
statementMap.clear();
return Collections.emptyList();
}
// 处理statement,编译sql,缓存相同sql的statement,并且设置参数
public Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 获取SQL的绑定信息
BoundSql boundSql = handler.getBoundSql();
// 获取SQL
String sql = boundSql.getSql();
// 使用缓存了当前SQL的statement对象
if (this.hasStatementFor(sql)) {
// 获取缓存的statement
stmt = this.getStatement(sql);
// 设置事务超时时间
applyTransactionTimeout(stmt);
} else {
// 获取连接
Connection connection = this.getConnection(statementLog);
// 编译SQL
stmt = handler.prepare(connection, transaction.getTimeout());
// 缓存当前sql对应的statement
this.putStatement(sql, stmt);
}
// 使用Statement处理器设置参数
handler.parameterize(stmt);
return stmt;
}
}
// 批量执行的执行器
public class BatchExecutor extends BaseExecutor {
// 批量更新返回的值(为固定值)
public static int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;
// 缓存的statement,遇到执行的statemntId(sql)不一样就会将该statement缓存下来,如果一样,则直接从该缓存中获取statement,则这样就不需要重复编译SQL等操作
public List<Statement> statementList = new ArrayList<>();
// 缓存的批量结果,批量结果中保存了statementId,sql,和参数信息
public List<BatchResult> batchResultList = new ArrayList<>();
// 当前缓存执行的SQL,如果SQL发生改变,一定是最新一次的SQL
public String currentSql;
// 当前缓存的Statement(<insert,select...>)映射语句详细信息,如果SQL发生改变,一定是最新一次的MappedStatement
public MappedStatement currentStatement;
// 更新操作
@Override
public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
// 获取配置信息
Configuration configuration = ms.getConfiguration();
// 创建Statement处理器,并执行插件,用来处理Statement
StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
// 获取SQL的绑定信息
BoundSql boundSql = handler.getBoundSql();
// 获取sql
String sql = boundSql.getSql();
Statement stmt;
// 当sql和执行的映射语句没有发生改变(第一次执行就会缓存,第二次就可以直接从缓存中获取)
if (sql.equals(currentSql) && ms.equals(currentStatement)) {
// 获取最后一次执行的statemnet
int last = statementList.size() - 1;
stmt = statementList.get(last);
// 设置事务超时时间
applyTransactionTimeout(stmt);
// 使用Statement处理器设置参数
handler.parameterize(stmt);
// 获取缓存的批量结果对象
BatchResult batchResult = batchResultList.get(last);
// 将该参数保存到批量的结果对象中
batchResult.addParameterObject(parameterObject);
}
// sql或者映射语句发生改变
else {
// 重新获取连接
Connection connection = this.getConnection(ms.getStatementLog());
// 预处理编译SQL
stmt = handler.prepare(connection, transaction.getTimeout());
// 使用Statement处理器设置参数
handler.parameterize(stmt);
// 缓存SQL和当前映射语句的详细信息MappedStatement
currentSql = sql;
currentStatement = ms;
// 缓存编译sql之后获得的statement对象
statementList.add(stmt);
// 保存批量结果对象,该结果对象包含执行的映射语句详细信息和SQL以及参数信息
batchResultList.add(new BatchResult(ms, sql, parameterObject));
}
// 使用Statement执行批量操作
handler.batch(stmt);
// 返回固定的批量更新的值
return BATCH_UPDATE_RETURN_VALUE;
}
// 查询操作
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
// 刷新所有缓存的statement
flushStatements();
// 获取配置信息
Configuration configuration = ms.getConfiguration();
// 创建Statement处理器,并执行插件,用来处理Statement
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
// 重新获取连接
Connection connection = this.getConnection(ms.getStatementLog());
// 预处理编译SQL
stmt = handler.prepare(connection, transaction.getTimeout());
// 使用Statement处理器设置参数
handler.parameterize(stmt);
// 执行statement处理器的查询操作
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
// 游标查询操作
@Override
protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
// 刷新所有缓存的statement
flushStatements();
// 获取配置信息
Configuration configuration = ms.getConfiguration();
// 创建Statement处理器,并执行插件,用来处理Statement
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
// 重新获取连接
Connection connection = this.getConnection(ms.getStatementLog());
// 预处理编译SQL
Statement stmt = handler.prepare(connection, transaction.getTimeout());
// 使用Statement处理器设置参数
handler.parameterize(stmt);
// 执行statement处理器的游标查询操作
Cursor<E> cursor = handler.queryCursor(stmt);
stmt.closeOnCompletion();
return cursor;
}
// 刷新所有缓存的statement
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
try {
List<BatchResult> results = new ArrayList<>();
if (isRollback) {
return Collections.emptyList();
}
// 遍历缓存的所有statement
for (int i = 0, n = statementList.size(); i < n; i++) {
// 获取statement
Statement stmt = statementList.get(i);
// 设置事务超时时间
applyTransactionTimeout(stmt);
// 获取statement对应的缓存的批量结果对象
BatchResult batchResult = batchResultList.get(i);
try {
// 执行statement的批量操作,并将批量执行的结果保存到批量结果对象中
batchResult.setUpdateCounts(stmt.executeBatch());
// 获取执行的映射语句SQL
MappedStatement ms = batchResult.getMappedStatement();
// 获取批量结果对象中缓存的所有参数
List<Object> parameterObjects = batchResult.getParameterObjects();
// 获取主键生成器
KeyGenerator keyGenerator = ms.getKeyGenerator();
if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
// 执行主键生成器的执行批量处理之后的逻辑
jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
} else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) {
// 遍历批量结果对象中缓存的所有参数
for (Object parameter : parameterObjects) {
// 给每一个参数执行主键生成器的执行批量处理之后的逻辑
keyGenerator.processAfter(this, ms, stmt, parameter);
}
}
// 关闭statemnt
closeStatement(stmt);
} catch (BatchUpdateException e) {
throw new BatchExecutorException(message.toString(), e, results, batchResult);
}
// 保存当前处理的tatement对应的缓存的批量结果对象,最终需要返回
results.add(batchResult);
}
return results;
} finally {
// 关闭缓存的所有Statement
for (Statement stmt : statementList) {
closeStatement(stmt);
}
// 重置缓存sql等信息
currentSql = null;
statementList.clear();
batchResultList.clear();
}
}
}
// 带有缓存的执行器
public class CachingExecutor implements Executor {
// 装饰模式,实际执行SQL的执行器
public Executor delegate;
// 事务缓存管理器,内部同时管理着多个一级缓存,也就是一个SQL可以从多个一级缓存中获取数据,可以跨Mapper.xml的缓存,也就是二级缓存
public TransactionalCacheManager tcm = new TransactionalCacheManager();
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
// 将当前执行器设置为代理执行器的包装对象
delegate.setExecutorWrapper(this);
}
@Override
public Transaction getTransaction() {
return delegate.getTransaction();
}
// 关闭执行器
@Override
public void close(boolean forceRollback) {
try {
// 处理缓存
// 如果需要强制回滚
if (forceRollback) {
// 缓存回滚
tcm.rollback();
return;
}
// 缓存提交
tcm.commit();
} finally {
// 关闭执行器
delegate.close(forceRollback);
}
}
@Override
public boolean isClosed() {
return delegate.isClosed();
}
// 更新操作
@Override
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
// 刷新缓存如果需要
flushCacheIfRequired(ms);
return delegate.update(ms, parameterObject);
}
@Override
public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {
// 刷新缓存如果需要
flushCacheIfRequired(ms);
return delegate.queryCursor(ms, parameter, rowBounds);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
// 创建缓存KEY
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
// 查询操作
return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
// 获取该映射语句需要使用的缓存,就是每一个mapper对应的一个缓存的那个缓存(二级缓存)
Cache cache = ms.getCache();
// 如果存在缓存
if (cache != null) {
// 刷新缓存如果需要
flushCacheIfRequired(ms);
// 当前映射语句需要使用缓存,并且没有设置结果集处理器,如果存在结果集处理器,就不会使用缓存
if (ms.isUseCache() && resultHandler == null) {
// 校验存在过程的输出参数,如果存在输出参数,则抛出异常
ensureNoOutParams(ms, boundSql);
// 从缓存中获取数据
List<E> list = (List<E>) tcm.getObject(cache, key);
// 如果不存在缓存
if (list == null) {
// 使用委托执行器执行查询操作
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
// 缓存当前结果
tcm.putObject(cache, key, list);
}
// 返回结果
return list;
}
}
// 不存在缓存
// 使用委托执行器执行查询操作
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public List<BatchResult> flushStatements() throws SQLException {
return delegate.flushStatements();
}
@Override
public void commit(boolean required) throws SQLException {
delegate.commit(required);
// 执行缓存管理器的提交操作,缓存也需要提交
tcm.commit();
}
@Override
public void rollback(boolean required) throws SQLException {
delegate.rollback(required);
// 如果必须回滚
if (required) {
// 执行缓存管理器的回滚操作,缓存也需要回滚
tcm.rollback();
}
}
public 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.");
}
}
}
}
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
return delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql);
}
@Override
public boolean isCached(MappedStatement ms, CacheKey key) {
return delegate.isCached(ms, key);
}
@Override
public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) {
delegate.deferLoad(ms, resultObject, property, key, targetType);
}
@Override
public void clearLocalCache() {
delegate.clearLocalCache();
}
// 刷新缓存如果有必要
public void flushCacheIfRequired(MappedStatement ms) {
// 获取该映射语句需要使用的缓存,就是每一个mapper对应的一个缓存的那个缓存
Cache cache = ms.getCache();
// 如果存在缓存,并且设置了必须刷新缓存
if (cache != null && ms.isFlushCacheRequired()) {
// 清空二级缓存
tcm.clear(cache);
}
}
@Override
public void setExecutorWrapper(Executor executor) {
throw new UnsupportedOperationException("This method should not be called");
}
}
}
// Mapper映射SQL的表示形式
// 就是解析(select|insert...)标签的信息
public class MappedStatement {
// 当前所有的mapper.xml资源
public String resource;
// 配置类信息
public Configuration configuration;
// statement(select|insert...)的id
// 命名空间+方法名
public String id;
// 这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值
public Integer fetchSize;
// 在抛出异常之前,驱动程序等待数据库返回请求结果的秒数
public Integer timeout;
// Statement的类型
public StatementType statementType;
// 结果集的类型FORWARD_ONfinally,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT 中的一个
public ResultSetType resultSetType;
// 该标签提供的SQL的分类
public SqlSource sqlSource;
// 该标签需要使用的缓存
public Cache cache;
// 该标签需要使用的参数映射
public ParameterMap parameterMap;
/**
* 该标签需要使用的结果集映射,可能会存在多结果集的对应多个resultMap,正常情况下都只会有一个
* <pre>
* <select id="getUserAndOrders" parameterType="int" resultSets="a,b" resultMap="userResultMap, orderResultMap">
* SELECT u.id as user_id, u.name as user_name, o.id as order_id, o.amount as order_amount
* FROM users u
* JOIN orders o ON u.id = o.user_id WHERE u.id = #{userId}
* </select>
* </pre>
*/
public List<ResultMap> resultMaps;
// 这个SQL是否需要刷新缓存
public boolean flushCacheRequired;
// 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来
// 默认值:对 select 元素为 true
public boolean useCache;
// 该属性决定是否使用查询结果进行映射(默认为false)
// 如果为true: 那么结果映射的时候会按照sql的查询列的顺序进行一一映射
// 如果为false: 那么就会按照resultMap设置的列的顺序进行映射
public boolean resultOrdered;
// SQL的类型
public SqlCommandType sqlCommandType;
// 主键的生成器
public KeyGenerator keyGenerator;
// 自动生成的主键需要映射的java属性
public String[] keyProperties;
// 自动生成的主键需要映射的表字段
public String[] keyColumns;
// paramMap是否存在嵌套的resultMap
public boolean hasNestedResultMaps;
// 使用的数据库Id
public String databaseId;
// 打印日志的对象
public Log statementLog;
// 执行该SQL的语言模板解析对象
public LanguageDriver lang;
// 这个设置仅适用于多结果集的情况
// 它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。
public String[] resultSets;
// 当执行INSERT、UPDATE或DELETE语句返回数据时会标记为true,来正确地控制事务
// 判断是否为脏查询
public boolean dirtySelect;
public static class Builder {
public 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;
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 MappedStatement build() {
return mappedStatement;
}
}
// 获取SQL的绑定信息
public BoundSql getBoundSql(Object parameterObject) {
// 获取SQL的绑定细腻
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
// 获取该SQL需要使用的参数映射
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// 如果不存在参数映射信息
if (parameterMappings == null || parameterMappings.isEmpty()) {
// 创建一个新的BoundSql
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// 检查参数映射中的嵌套结果映射
// <parameterMap id="" type="">
// 也就是id属性使用resultMap的映射方式,将java参数对象映射到SQL参数中
// <parameter property="id" resultMap="rm"></parameter>
// </parameterMap>
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
// 是否存在嵌套的resultMap
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
}
// 游标类型的结果对象,它相对使用selectList而言,优势在于不会加载所有结果到内存中,而是一条一条数据的处理
// 它节省内存,适合在大批量操作下使用
public class DefaultCursor<T> implements Cursor<T> {
// 结果集处理器
private final ResultSetHandler.DefaultResultSetHandler resultSetHandler;
// 结果集映射信息
private final ResultMap resultMap;
// 结果集对象
private final ResultSetWrapper rsw;
// 分页参数
private final RowBounds rowBounds;
// 结果处理器的包装对象
protected final ObjectWrapperResultHandler<T> objectWrapperResultHandler = new ObjectWrapperResultHandler<>();
// 游标的迭代器
private final CursorIterator cursorIterator = new CursorIterator();
// 迭代器时候被打开,也就是当前对象只能调用一次iterator()来获取迭代器对象
private boolean iteratorRetrieved;
// 游标状态
private CursorStatus status = CursorStatus.CREATED;
private int indexWithRowBound = -1;
private enum CursorStatus {
// 创建
CREATED,
// 打开
OPEN,
// 关闭
CLOSED,
// 已消费
CONSUMED
}
@Override
public boolean isOpen() {
return status == CursorStatus.OPEN;
}
@Override
public boolean isConsumed() {
return status == CursorStatus.CONSUMED;
}
@Override
public int getCurrentIndex() {
return rowBounds.getOffset() + cursorIterator.iteratorIndex;
}
// 获取迭代器
@Override
public Iterator<T> iterator() {
if (iteratorRetrieved) {
throw new IllegalStateException("Cannot open more than one iterator on a Cursor");
}
if (isClosed()) {
throw new IllegalStateException("A Cursor is already closed.");
}
// 标记迭代器时候被打开
iteratorRetrieved = true;
return cursorIterator;
}
@Override
public void close() {
if (isClosed()) {
return;
}
ResultSet rs = rsw.getResultSet();
if (rs != null) {
rs.close();
}
status = CursorStatus.CLOSED;
}
// 使用分页条件拉取下一行记录
protected T fetchNextUsingRowBound() {
// 拉取结果集中的数据
T result = fetchNextObjectFromDatabase();
// 进行列偏移,跳到offset的位置结束
while (objectWrapperResultHandler.fetched && indexWithRowBound < rowBounds.getOffset()) {
// 拉取结果集中的数据
result = fetchNextObjectFromDatabase();
}
return result;
}
// 拉取结果集中的数据,一行一行拉取
protected T fetchNextObjectFromDatabase() {
if (isClosed()) {
return null;
}
// 重置标记,标记结果未被获取
objectWrapperResultHandler.fetched = false;
// 重置游标状态
status = CursorStatus.OPEN;
// 如果结果集未关闭,
if (!rsw.getResultSet().isClosed()) {
// 处理这一行的结果
resultSetHandler.handleRowValues(rsw, resultMap, objectWrapperResultHandler, RowBounds.DEFAULT, null);
}
// 获取这一行结果集映射好的结果对象
T next = objectWrapperResultHandler.result;
// 如果值已经被获取了,在处理结果集的时候,会使用objectWrapperResultHandler来处理,处理完一行结果,会标记为true
if (objectWrapperResultHandler.fetched) {
// 记录正在处理的行数
indexWithRowBound++;
}
// 如果未获取到值或者读取到结果的数量达到了分页限制
if (!objectWrapperResultHandler.fetched || getReadItemsCount() == rowBounds.getOffset() + rowBounds.getLimit()) {
// 关闭当前游标
close();
// 标记当前游标状态为已消费
status = CursorStatus.CONSUMED;
}
// 将处理的结果制空
objectWrapperResultHandler.result = null;
// 返回处理的结果
return next;
}
private boolean isClosed() {
return status == CursorStatus.CLOSED || status == CursorStatus.CONSUMED;
}
// 获取读取到的记录数
private int getReadItemsCount() {
return indexWithRowBound + 1;
}
// 对象包装器的结果处理器
protected static class ObjectWrapperResultHandler<T> implements ResultHandler<T> {
// 结果对象
protected T result;
// 是否被获取
protected boolean fetched;
@Override
public void handleResult(ResultContext<? extends T> context) {
// 获取结果对象
this.result = context.getResultObject();
// 终止处理结果
context.stop();
// 标记结果已被获取
fetched = true;
}
}
// 游标迭代器
protected class CursorIterator implements Iterator<T> {
// 需要返回的对象
T object;
// 迭代的次数
int iteratorIndex = -1;
@Override
public boolean hasNext() {
// 如果结果未被获取
if (!objectWrapperResultHandler.fetched) {
// 使用分页条件拉取下一行记录
object = fetchNextUsingRowBound();
}
// 返回结果处理器中的标记,当获取到值的情况下,fetched为true,否则为false
return objectWrapperResultHandler.fetched;
}
@Override
public T next() {
// 在hasNext的时候会获取当前行的值,除非手动操作,调用多次next操作
T next = object;
// 如果值未被获取,正常情况下hasNext中已经完成了这个操作
// 如果没有经过hasNext操作,也要给数据出来
if (!objectWrapperResultHandler.fetched) {
// 使用分页条件拉取下一行记录
next = fetchNextUsingRowBound();
}
// 如果值被获取了,重置标记,这样才能再次获取数据
if (objectWrapperResultHandler.fetched) {
// 重置标记
objectWrapperResultHandler.fetched = false;
// 重置结果对象
object = null;
// 迭代次数加+
iteratorIndex++;
// 返回来取的结果
return next;
}
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException("Cannot remove element from Cursor");
}
}
}