Mybatis源码分析之结果封装ResultSetHandler和DefaultResultSetHandler
ResultSetHandler是一个接口,提供了两个函数分别用来处理普通操作和存储过程的结果,
源码如下:
- /**
- * @author Clinton Begin
- */
- public interface ResultSetHandler {
- <E> List<E> handleResultSets(Statement stmt) throws SQLException;
- void handleOutputParameters(CallableStatement cs) throws SQLException;
- }
ResultSetHandler的具体实现类是DefaultResultSetHandler,其实现的步骤就是将Statement执行后的结果集,按照Mapper文件中配置的ResultType或ResultMap来封装成对应的对象,最后将封装的对象返回即可,
DefaultResultSetHandler源码如下:
- //ResultSetHandler具体实现类
- public class DefaultResultSetHandler implements ResultSetHandler {
- private static final Object DEFERED = new Object();
- private final Executor executor;
- private final Configuration configuration;
- private final MappedStatement mappedStatement;
- private final RowBounds rowBounds;
- private final ParameterHandler parameterHandler;
- private final ResultHandler<?> resultHandler;
- private final BoundSql boundSql;
- private final TypeHandlerRegistry typeHandlerRegistry;
- private final ObjectFactory objectFactory;
- private final ReflectorFactory reflectorFactory;
- // nested resultmaps
- // 此Map用来保存当前层级内部的结果对象(一对多关系的多方对象),key为combinedKey
- private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>();
- // 此Map用来保存当前层级的根对象(一对多关系中的一方对象),key为absoluteKey
- private final Map<CacheKey, Object> ancestorObjects = new HashMap<CacheKey, Object>();
- private final Map<String, String> ancestorColumnPrefix = new HashMap<String, String>();
- // multiple resultsets
- private final Map<String, ResultMapping> nextResultMaps = new HashMap<String, ResultMapping>();
- private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>();
- private static class PendingRelation {
- public MetaObject metaObject;
- public ResultMapping propertyMapping;
- }
- public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql,
- RowBounds rowBounds) {
- this.executor = executor;
- this.configuration = mappedStatement.getConfiguration();
- this.mappedStatement = mappedStatement;
- this.rowBounds = rowBounds;
- this.parameterHandler = parameterHandler;
- this.boundSql = boundSql;
- this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
- this.objectFactory = configuration.getObjectFactory();
- this.reflectorFactory = configuration.getReflectorFactory();
- this.resultHandler = resultHandler;
- }
- //
- // HANDLE OUTPUT PARAMETER
- //
- //调用存储过程返回结果,将结果值放在参数中
- @Override
- public void handleOutputParameters(CallableStatement cs) throws SQLException {
- final Object parameterObject = parameterHandler.getParameterObject();
- final MetaObject metaParam = configuration.newMetaObject(parameterObject);
- final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
- //循环处理每个参数
- for (int i = 0; i < parameterMappings.size(); i++) {
- final ParameterMapping parameterMapping = parameterMappings.get(i);
- //判断参数的模式
- if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
- if (ResultSet.class.equals(parameterMapping.getJavaType())) {
- handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
- } else {
- final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
- metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
- }
- }
- }
- }
- private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam) throws SQLException {
- try {
- final String resultMapId = parameterMapping.getResultMapId();
- final ResultMap resultMap = configuration.getResultMap(resultMapId);
- final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
- final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
- handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
- metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
- } finally {
- // issue #228 (close resultsets)
- closeResultSet(rs);
- }
- }
- //
- // HANDLE RESULT SETS
- //
- //对普通查询到的结果转换
- @Override
- public List<Object> handleResultSets(Statement stmt) throws SQLException {
- ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
- final List<Object> multipleResults = new ArrayList<Object>();
- int resultSetCount = 0;
- //获取第一个结果值
- ResultSetWrapper rsw = getFirstResultSet(stmt);
- //获得resultMap
- List<ResultMap> resultMaps = mappedStatement.getResultMaps();
- //这边应该为1吧,一般resultMap为一个
- int resultMapCount = resultMaps.size();
- //判断是否有resultMap,没有的话抛出异常
- validateResultMapsCount(rsw, resultMapCount);
- while (rsw != null && resultMapCount > resultSetCount) {
- //获得resultMap,实体类和表中数据字段的对应关系
- ResultMap resultMap = resultMaps.get(resultSetCount);
- //将值设置成对应的resultmap对象
- handleResultSet(rsw, resultMap, multipleResults, null);
- rsw = getNextResultSet(stmt);
- cleanUpAfterHandlingResultSet();
- resultSetCount++;
- }
- String[] resultSets = mappedStatement.getResulSets();
- if (resultSets != null) {
- while (rsw != null && resultSetCount < resultSets.length) {
- ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
- if (parentMapping != null) {
- String nestedResultMapId = parentMapping.getNestedResultMapId();
- ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
- handleResultSet(rsw, resultMap, null, parentMapping);
- }
- rsw = getNextResultSet(stmt);
- cleanUpAfterHandlingResultSet();
- resultSetCount++;
- }
- }
- return collapseSingleResultList(multipleResults);
- }
- //获得第一个值,并将值打包
- private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
- ResultSet rs = stmt.getResultSet();
- //结果集不为空
- while (rs == null) {
- // move forward to get the first resultset in case the driver
- // doesn't return the resultset as the first result (HSQLDB 2.1)
- if (stmt.getMoreResults()) {
- rs = stmt.getResultSet();
- } else {
- if (stmt.getUpdateCount() == -1) {
- // no more results. Must be no resultset
- break;
- }
- }
- }
- //将数据打包
- return rs != null ? new ResultSetWrapper(rs, configuration) : null;
- }
- //获取下一个值,将值打包
- private ResultSetWrapper getNextResultSet(Statement stmt) throws SQLException {
- // Making this method tolerant of bad JDBC drivers
- try {
- if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
- // Crazy Standard JDBC way of determining if there are more results
- if (!((!stmt.getMoreResults()) && (stmt.getUpdateCount() == -1))) {
- ResultSet rs = stmt.getResultSet();
- return rs != null ? new ResultSetWrapper(rs, configuration) : null;
- }
- }
- } catch (Exception e) {
- // Intentionally ignored.
- }
- return null;
- }
- //关闭resultSet
- private void closeResultSet(ResultSet rs) {
- try {
- if (rs != null) {
- rs.close();
- }
- } catch (SQLException e) {
- // ignore
- }
- }
- private void cleanUpAfterHandlingResultSet() {
- nestedResultObjects.clear();
- ancestorColumnPrefix.clear();
- }
- //校验结果的resultMap,如果没有的话就抛出异常
- private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) {
- if (rsw != null && resultMapCount < 1) {
- throw new ExecutorException("A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId()
- + "'. It's likely that neither a Result Type nor a Result Map was specified.");
- }
- }
- private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
- try {
- if (parentMapping != null) {
- handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
- } else {
- if (resultHandler == null) {
- // 创建一个新对象
- DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
- //将查询到的每个字段和Bean实体中的属性对应起来,生成一个Result对象
- handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
- //结果映射对象及值添加到multipleResults中
- multipleResults.add(defaultResultHandler.getResultList());
- } else {
- handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
- }
- }
- } finally {
- // issue #228 (close resultsets)
- closeResultSet(rsw.getResultSet());
- }
- }
- @SuppressWarnings("unchecked")
- private List<Object> collapseSingleResultList(List<Object> multipleResults) {
- return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
- }
- //
- // HANDLE ROWS FOR SIMPLE RESULTMAP
- //
- //操作列值
- private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
- if (resultMap.hasNestedResultMaps()) {
- ensureNoRowBounds();
- checkResultHandler();
- handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
- } else {
- handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
- }
- }
- //判断记录行数
- private void ensureNoRowBounds() {
- if (configuration.isSafeRowBoundsEnabled() && rowBounds != null && (rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT || rowBounds.getOffset() > RowBounds.NO_ROW_OFFSET)) {
- throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. "
- + "Use safeRowBoundsEnabled=false setting to bypass this check.");
- }
- }
- protected void checkResultHandler() {
- if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.isResultOrdered()) {
- throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely used with a custom ResultHandler. "
- + "Use safeResultHandlerEnabled=false setting to bypass this check "
- + "or ensure your statement returns ordered data and set resultOrdered=true on it.");
- }
- }
- private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
- throws SQLException {
- DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
- //跳过RowBounds设置的offset值
- skipRows(rsw.getResultSet(), rowBounds);
- //判断数据是否小于limit,如果小于limit的话就不断的循环取值
- while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
- ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
- Object rowValue = getRowValue(rsw, discriminatedResultMap);
- storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
- }
- }
- private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
- if (parentMapping != null) {
- linkToParents(rs, parentMapping, rowValue);
- } else {
- callResultHandler(resultHandler, resultContext, rowValue);
- }
- }
- @SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object>*/)
- private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
- resultContext.nextResultObject(rowValue);
- ((ResultHandler<Object>)resultHandler).handleResult(resultContext);
- }
- private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) throws SQLException {
- //判断数据是否小于limit,小于返回true
- return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
- }
- //跳过不需要的行,应该就是rowbounds设置的limit和offset
- private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
- if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
- if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
- rs.absolute(rowBounds.getOffset());
- }
- } else {
- //跳过RowBounds中设置的offset条数据
- for (int i = 0; i < rowBounds.getOffset(); i++) {
- rs.next();
- }
- }
- }
- //
- // GET VALUE FROM ROW FOR SIMPLE RESULT MAP
- //
- private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
- final ResultLoaderMap lazyLoader = new ResultLoaderMap();
- //结果的映射对象
- Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
- if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
- final MetaObject metaObject = configuration.newMetaObject(resultObject);
- boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
- if (shouldApplyAutomaticMappings(resultMap, false)) {
- foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
- }
- foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
- foundValues = lazyLoader.size() > 0 || foundValues;
- resultObject = foundValues ? resultObject : null;
- return resultObject;
- }
- return resultObject;
- }
- //用于判断是否是bean实体变量和表中字段自动映射
- private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
- if (resultMap.getAutoMapping() != null) {
- return resultMap.getAutoMapping();
- } else {
- if (isNested) {
- return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();
- } else {
- return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
- }
- }
- }
- //
- // PROPERTY MAPPINGS
- //
- private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
- throws SQLException {
- final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
- boolean foundValues = false;
- final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
- for (ResultMapping propertyMapping : propertyMappings) {
- String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
- if (propertyMapping.getNestedResultMapId() != null) {
- // the user added a column attribute to a nested result map, ignore it
- column = null;
- }
- if (propertyMapping.isCompositeResult()
- || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
- || propertyMapping.getResultSet() != null) {
- Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
- // issue #541 make property optional
- final String property = propertyMapping.getProperty();
- // issue #377, call setter on nulls
- if (value != DEFERED
- && property != null
- && (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive()))) {
- metaObject.setValue(property, value);
- }
- if (value != null || value == DEFERED) {
- foundValues = true;
- }
- }
- }
- return foundValues;
- }
- private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
- throws SQLException {
- if (propertyMapping.getNestedQueryId() != null) {
- return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
- } else if (propertyMapping.getResultSet() != null) {
- addPendingChildRelation(rs, metaResultObject, propertyMapping); // TODO is that OK?
- return DEFERED;
- } else {
- final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
- final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
- return typeHandler.getResult(rs, column);
- }
- }
- //
- private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
- final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
- boolean foundValues = false;
- //获得列名
- for (String columnName : unmappedColumnNames) {
- String propertyName = columnName;
- if (columnPrefix != null && !columnPrefix.isEmpty()) {
- // When columnPrefix is specified,
- // ignore columns without the prefix.
- if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
- propertyName = columnName.substring(columnPrefix.length());
- } else {
- continue;
- }
- }
- final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
- if (property != null && metaObject.hasSetter(property)) {
- final Class<?> propertyType = metaObject.getSetterType(property);
- if (typeHandlerRegistry.hasTypeHandler(propertyType)) {
- final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
- final Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
- // issue #377, call setter on nulls
- if (value != null || configuration.isCallSettersOnNulls()) {
- if (value != null || !propertyType.isPrimitive()) {
- metaObject.setValue(property, value);
- }
- foundValues = true;
- }
- }
- }
- }
- return foundValues;
- }
- // MULTIPLE RESULT SETS
- private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
- CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn());
- List<PendingRelation> parents = pendingRelations.get(parentKey);
- if (parents != null) {
- for (PendingRelation parent : parents) {
- if (parent != null && rowValue != null) {
- linkObjects(parent.metaObject, parent.propertyMapping, rowValue);
- }
- }
- }
- }
- private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping) throws SQLException {
- CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getColumn());
- PendingRelation deferLoad = new PendingRelation();
- deferLoad.metaObject = metaResultObject;
- deferLoad.propertyMapping = parentMapping;
- List<PendingRelation> relations = pendingRelations.get(cacheKey);
- // issue #255
- if (relations == null) {
- relations = new ArrayList<DefaultResultSetHandler.PendingRelation>();
- pendingRelations.put(cacheKey, relations);
- }
- relations.add(deferLoad);
- ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
- if (previous == null) {
- nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
- } else {
- if (!previous.equals(parentMapping)) {
- throw new ExecutorException("Two different properties are mapped to the same resultSet");
- }
- }
- }
- private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns) throws SQLException {
- CacheKey cacheKey = new CacheKey();
- cacheKey.update(resultMapping);
- if (columns != null && names != null) {
- String[] columnsArray = columns.split(",");
- String[] namesArray = names.split(",");
- for (int i = 0 ; i < columnsArray.length ; i++) {
- Object value = rs.getString(columnsArray[i]);
- if (value != null) {
- cacheKey.update(namesArray[i]);
- cacheKey.update(value);
- }
- }
- }
- return cacheKey;
- }
- //
- // INSTANTIATION & CONSTRUCTOR MAPPING
- //
- //创建结果对象
- private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
- final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
- final List<Object> constructorArgs = new ArrayList<Object>();
- //结果对象
- final Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
- if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
- //获取配置的resultMap的字段与表中数据的映射关系
- final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
- for (ResultMapping propertyMapping : propertyMappings) {
- // issue gcode #109 && issue #149
- if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
- return configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
- }
- }
- }
- return resultObject;
- }
- //创建结果对象
- private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
- throws SQLException {
- //结果类型
- final Class<?> resultType = resultMap.getType();
- //通过反射获取结果对象
- final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
- final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
- if (typeHandlerRegistry.hasTypeHandler(resultType)) {
- //基本类型
- return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
- } else if (!constructorMappings.isEmpty()) {
- //有参数构造函数
- return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
- } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
- //普通的bean类型
- return objectFactory.create(resultType);
- } else if (shouldApplyAutomaticMappings(resultMap, false)) {
- //自动映射
- return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
- }
- throw new ExecutorException("Do not know how to create an instance of " + resultType);
- }
- //有参数构造函数
- Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings,
- List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) {
- boolean foundValues = false;
- for (ResultMapping constructorMapping : constructorMappings) {
- final Class<?> parameterType = constructorMapping.getJavaType();
- final String column = constructorMapping.getColumn();
- final Object value;
- try {
- if (constructorMapping.getNestedQueryId() != null) {
- value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
- } else if (constructorMapping.getNestedResultMapId() != null) {
- final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
- value = getRowValue(rsw, resultMap);
- } else {
- final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
- value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
- }
- } catch (ResultMapException e) {
- throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
- } catch (SQLException e) {
- throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
- }
- constructorArgTypes.add(parameterType);
- constructorArgs.add(value);
- foundValues = value != null || foundValues;
- }
- return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
- }
- //自动映射
- private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs,
- String columnPrefix) throws SQLException {
- for (Constructor<?> constructor : resultType.getDeclaredConstructors()) {
- if (typeNames(constructor.getParameterTypes()).equals(rsw.getClassNames())) {
- boolean foundValues = false;
- for (int i = 0; i < constructor.getParameterTypes().length; i++) {
- Class<?> parameterType = constructor.getParameterTypes()[i];
- String columnName = rsw.getColumnNames().get(i);
- TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
- Object value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(columnName, columnPrefix));
- constructorArgTypes.add(parameterType);
- constructorArgs.add(value);
- foundValues = value != null || foundValues;
- }
- return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
- }
- }
- throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
- }
- private List<String> typeNames(Class<?>[] parameterTypes) {
- List<String> names = new ArrayList<String>();
- for (Class<?> type : parameterTypes) {
- names.add(type.getName());
- }
- return names;
- }
- //创建原型结果
- private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
- final Class<?> resultType = resultMap.getType();
- final String columnName;
- if (!resultMap.getResultMappings().isEmpty()) {
- final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
- final ResultMapping mapping = resultMappingList.get(0);
- columnName = prependPrefix(mapping.getColumn(), columnPrefix);
- } else {
- columnName = rsw.getColumnNames().get(0);
- }
- final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
- return typeHandler.getResult(rsw.getResultSet(), columnName);
- }
- //
- // NESTED QUERY
- //
- private Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix) throws SQLException {
- final String nestedQueryId = constructorMapping.getNestedQueryId();
- final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
- final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
- final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping, nestedQueryParameterType, columnPrefix);
- Object value = null;
- if (nestedQueryParameterObject != null) {
- final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
- final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
- final Class<?> targetType = constructorMapping.getJavaType();
- final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
- value = resultLoader.loadResult();
- }
- return value;
- }
- //得到嵌套查询值
- private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
- throws SQLException {
- final String nestedQueryId = propertyMapping.getNestedQueryId();
- final String property = propertyMapping.getProperty();
- final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
- final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
- final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix);
- Object value = null;
- if (nestedQueryParameterObject != null) {
- final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
- final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
- final Class<?> targetType = propertyMapping.getJavaType();
- if (executor.isCached(nestedQuery, key)) {
- //如果已经有一级缓存了,则延迟加载(实际上deferLoad方法中可以看到则是立即加载)
- executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
- value = DEFERED;
- } else {
- //否则lazyLoader.addLoader 需要延迟加载则addLoader
- //或者ResultLoader.loadResult 不需要延迟加载则立即加载
- final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
- if (propertyMapping.isLazy()) {
- lazyLoader.addLoader(property, metaResultObject, resultLoader);
- value = DEFERED;
- } else {
- value = resultLoader.loadResult();
- }
- }
- }
- return value;
- }
- private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
- if (resultMapping.isCompositeResult()) {
- return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
- } else {
- return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
- }
- }
- private Object prepareSimpleKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
- final TypeHandler<?> typeHandler;
- if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
- typeHandler = typeHandlerRegistry.getTypeHandler(parameterType);
- } else {
- typeHandler = typeHandlerRegistry.getUnknownTypeHandler();
- }
- return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
- }
- private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException {
- final Object parameterObject = instantiateParameterObject(parameterType);
- final MetaObject metaObject = configuration.newMetaObject(parameterObject);
- boolean foundValues = false;
- for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
- final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());
- final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);
- final Object propValue = typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix));
- // issue #353 & #560 do not execute nested query if key is null
- if (propValue != null) {
- metaObject.setValue(innerResultMapping.getProperty(), propValue);
- foundValues = true;
- }
- }
- return foundValues ? parameterObject : null;
- }
- private Object instantiateParameterObject(Class<?> parameterType) {
- if (parameterType == null) {
- return new HashMap<Object, Object>();
- } else {
- return objectFactory.create(parameterType);
- }
- }
- //
- // DISCRIMINATOR
- //
- public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
- Set<String> pastDiscriminators = new HashSet<String>();
- Discriminator discriminator = resultMap.getDiscriminator();
- while (discriminator != null) {
- final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
- final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
- if (configuration.hasResultMap(discriminatedMapId)) {
- resultMap = configuration.getResultMap(discriminatedMapId);
- Discriminator lastDiscriminator = discriminator;
- discriminator = resultMap.getDiscriminator();
- if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
- break;
- }
- } else {
- break;
- }
- }
- return resultMap;
- }
- private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException {
- final ResultMapping resultMapping = discriminator.getResultMapping();
- final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
- return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
- }
- private String prependPrefix(String columnName, String prefix) {
- if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {
- return columnName;
- }
- return prefix + columnName;
- }
- //
- // HANDLE NESTED RESULT MAPS
- //
- //生成嵌套对象值
- private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
- //创建默认结果上下文
- final DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
- //跳过rowBounds指定offset行偏移量
- skipRows(rsw.getResultSet(), rowBounds);
- Object rowValue = null;
- //如何定义应该处理:上下文没有主动停止,结果集还有记录,且上下文中结果对象数量不足时,应该继续处理
- while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
- // 解决鉴别过的结果映射,逻辑如下:
- // 获取结果映射中的鉴别器,通过鉴别指定字段通过配置对象获取对应的另一个结果映射,循环往复,
- // 直到找不到鉴别器为止,返回最终的结果映射
- final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
- // 创建缓存key,如何创建?
- final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
- // 缓存中获取结果对象
- Object partialObject = nestedResultObjects.get(rowKey);
- // issue #577 && #542
- if (mappedStatement.isResultOrdered()) {
- if (partialObject == null && rowValue != null) {
- nestedResultObjects.clear();
- // 保存结果对象
- storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
- }
- // 获取行值
- rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);
- } else {
- rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);
- if (partialObject == null) {
- storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
- }
- }
- }
- if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
- storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
- }
- }
- //
- // GET VALUE FROM ROW FOR NESTED RESULT MAP
- //
- //
- private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, CacheKey absoluteKey, String columnPrefix, Object partialObject) throws SQLException {
- final String resultMapId = resultMap.getId();
- Object resultObject = partialObject;
- if (resultObject != null) {
- final MetaObject metaObject = configuration.newMetaObject(resultObject);
- putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
- applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
- ancestorObjects.remove(absoluteKey);
- } else {
- final ResultLoaderMap lazyLoader = new ResultLoaderMap();
- resultObject = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
- if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
- final MetaObject metaObject = configuration.newMetaObject(resultObject);
- boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
- if (shouldApplyAutomaticMappings(resultMap, true)) {
- foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
- }
- foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
- putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
- foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
- ancestorObjects.remove(absoluteKey);
- foundValues = lazyLoader.size() > 0 || foundValues;
- resultObject = foundValues ? resultObject : null;
- }
- if (combinedKey != CacheKey.NULL_CACHE_KEY) {
- nestedResultObjects.put(combinedKey, resultObject);
- }
- }
- return resultObject;
- }
- private void putAncestor(CacheKey rowKey, Object resultObject, String resultMapId, String columnPrefix) {
- if (!ancestorColumnPrefix.containsKey(resultMapId)) {
- ancestorColumnPrefix.put(resultMapId, columnPrefix);
- }
- ancestorObjects.put(rowKey, resultObject);
- }
- //
- // NESTED RESULT MAP (JOIN MAPPING)
- //
- private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
- boolean foundValues = false;
- for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
- final String nestedResultMapId = resultMapping.getNestedResultMapId();
- if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
- try {
- final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
- final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
- CacheKey rowKey = null;
- Object ancestorObject = null;
- if (ancestorColumnPrefix.containsKey(nestedResultMapId)) {
- rowKey = createRowKey(nestedResultMap, rsw, ancestorColumnPrefix.get(nestedResultMapId));
- ancestorObject = ancestorObjects.get(rowKey);
- }
- if (ancestorObject != null) {
- if (newObject) {
- linkObjects(metaObject, resultMapping, ancestorObject); // issue #385
- }
- } else {
- rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
- final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
- Object rowValue = nestedResultObjects.get(combinedKey);
- boolean knownValue = (rowValue != null);
- instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory
- if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw.getResultSet())) {
- rowValue = getRowValue(rsw, nestedResultMap, combinedKey, rowKey, columnPrefix, rowValue);
- if (rowValue != null && !knownValue) {
- linkObjects(metaObject, resultMapping, rowValue);
- foundValues = true;
- }
- }
- }
- } catch (SQLException e) {
- throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'. Cause: " + e, e);
- }
- }
- }
- return foundValues;
- }
- private String getColumnPrefix(String parentPrefix, ResultMapping resultMapping) {
- final StringBuilder columnPrefixBuilder = new StringBuilder();
- if (parentPrefix != null) {
- columnPrefixBuilder.append(parentPrefix);
- }
- if (resultMapping.getColumnPrefix() != null) {
- columnPrefixBuilder.append(resultMapping.getColumnPrefix());
- }
- return columnPrefixBuilder.length() == 0 ? null : columnPrefixBuilder.toString().toUpperCase(Locale.ENGLISH);
- }
- private boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSet rs) throws SQLException {
- Set<String> notNullColumns = resultMapping.getNotNullColumns();
- boolean anyNotNullColumnHasValue = true;
- if (notNullColumns != null && !notNullColumns.isEmpty()) {
- anyNotNullColumnHasValue = false;
- for (String column: notNullColumns) {
- rs.getObject(prependPrefix(column, columnPrefix));
- if (!rs.wasNull()) {
- anyNotNullColumnHasValue = true;
- break;
- }
- }
- }
- return anyNotNullColumnHasValue;
- }
- private ResultMap getNestedResultMap(ResultSet rs, String nestedResultMapId, String columnPrefix) throws SQLException {
- ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId);
- return resolveDiscriminatedResultMap(rs, nestedResultMap, columnPrefix);
- }
- //
- // UNIQUE RESULT KEY
- //
- private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {
- final CacheKey cacheKey = new CacheKey();
- cacheKey.update(resultMap.getId());
- List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);
- if (resultMappings.size() == 0) {
- if (Map.class.isAssignableFrom(resultMap.getType())) {
- createRowKeyForMap(rsw, cacheKey);
- } else {
- createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
- }
- } else {
- createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
- }
- return cacheKey;
- }
- private CacheKey combineKeys(CacheKey rowKey, CacheKey parentRowKey) {
- if (rowKey.getUpdateCount() > 1 && parentRowKey.getUpdateCount() > 1) {
- CacheKey combinedKey;
- try {
- combinedKey = rowKey.clone();
- } catch (CloneNotSupportedException e) {
- throw new ExecutorException("Error cloning cache key. Cause: " + e, e);
- }
- combinedKey.update(parentRowKey);
- return combinedKey;
- }
- return CacheKey.NULL_CACHE_KEY;
- }
- private List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) {
- List<ResultMapping> resultMappings = resultMap.getIdResultMappings();
- if (resultMappings.size() == 0) {
- resultMappings = resultMap.getPropertyResultMappings();
- }
- return resultMappings;
- }
- private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, List<ResultMapping> resultMappings, String columnPrefix) throws SQLException {
- for (ResultMapping resultMapping : resultMappings) {
- if (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null) {
- // Issue #392
- final ResultMap nestedResultMap = configuration.getResultMap(resultMapping.getNestedResultMapId());
- createRowKeyForMappedProperties(nestedResultMap, rsw, cacheKey, nestedResultMap.getConstructorResultMappings(),
- prependPrefix(resultMapping.getColumnPrefix(), columnPrefix));
- } else if (resultMapping.getNestedQueryId() == null) {
- final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
- final TypeHandler<?> th = resultMapping.getTypeHandler();
- List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
- // Issue #114
- if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {
- final Object value = th.getResult(rsw.getResultSet(), column);
- if (value != null) {
- cacheKey.update(column);
- cacheKey.update(value);
- }
- }
- }
- }
- }
- private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, String columnPrefix) throws SQLException {
- final MetaClass metaType = MetaClass.forClass(resultMap.getType(), reflectorFactory);
- List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
- for (String column : unmappedColumnNames) {
- String property = column;
- if (columnPrefix != null && !columnPrefix.isEmpty()) {
- // When columnPrefix is specified, ignore columns without the prefix.
- if (column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
- property = column.substring(columnPrefix.length());
- } else {
- continue;
- }
- }
- if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {
- String value = rsw.getResultSet().getString(column);
- if (value != null) {
- cacheKey.update(column);
- cacheKey.update(value);
- }
- }
- }
- }
- private void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException {
- List<String> columnNames = rsw.getColumnNames();
- for (String columnName : columnNames) {
- final String value = rsw.getResultSet().getString(columnName);
- if (value != null) {
- cacheKey.update(columnName);
- cacheKey.update(value);
- }
- }
- }
- private void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue) {
- final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
- if (collectionProperty != null) {
- final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
- targetMetaObject.add(rowValue);
- } else {
- metaObject.setValue(resultMapping.getProperty(), rowValue);
- }
- }
- private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {
- final String propertyName = resultMapping.getProperty();
- Object propertyValue = metaObject.getValue(propertyName);
- if (propertyValue == null) {
- Class<?> type = resultMapping.getJavaType();
- if (type == null) {
- type = metaObject.getSetterType(propertyName);
- }
- try {
- if (objectFactory.isCollection(type)) {
- propertyValue = objectFactory.create(type);
- metaObject.setValue(propertyName, propertyValue);
- return propertyValue;
- }
- } catch (Exception e) {
- throw new ExecutorException("Error instantiating collection property for result '" + resultMapping.getProperty() + "'. Cause: " + e, e);
- }
- } else if (objectFactory.isCollection(propertyValue.getClass())) {
- return propertyValue;
- }
- return null;
- }
- }
Mybatis源码分析之结果封装ResultSetHandler和DefaultResultSetHandler的更多相关文章
- mybatis 源码分析(八)ResultSetHandler 详解
本篇博客就是 myabtis 系列的最后一篇了,还剩 ResultSetHandler 没有分析:作为整个 mybatis 最复杂最繁琐的部分,我不打算按步骤一次详解,因为里面的主要内容就是围绕 re ...
- 精尽MyBatis源码分析 - SQL执行过程(三)之 ResultSetHandler
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- MyBatis源码分析-SQL语句执行的完整流程
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- 【MyBatis源码分析】select源码分析及小结
示例代码 之前的文章说过,对于MyBatis来说insert.update.delete是一组的,因为对于MyBatis来说它们都是update:select是一组的,因为对于MyBatis来说它就是 ...
- Mybatis源码分析-StatementHandler
承接前文Mybatis源码分析-BaseExecutor,本文则对通过StatementHandler接口完成数据库的CRUD操作作简单的分析 StatementHandler#接口列表 //获取St ...
- MyBatis 源码分析 - 插件机制
1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展.这样的好处是显而易见的,一是增加了框架的灵活性.二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作.以 My ...
- MyBatis 源码分析 - 配置文件解析过程
* 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...
- Mybatis源码分析
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- Mybatis源码分析之SqlSession和Excutor(二)
通过上一篇文章的分析我们,我初步了解了它是如何创建sessionFactory的(地址:Mybatis源码分析之SqlSessionFactory(一)), 今天我们分析下Mybatis如何创建Sql ...
随机推荐
- Debugging TensorFlow models 调试 TensorFlow 模型
Debugging TensorFlow models Symbolic nature of TensorFlow makes it relatively more difficult to debu ...
- java集合之HashMap源码解读
源自:jdk1.8.0_121 HashMap继承自AbstractMap,实现了Map.Cloneable.Serializable. HashMap内部是由数组.链表.红黑树实现的 变量 // 默 ...
- SpringMVC中url-pattern /和/*的区别
http://blog.csdn.net/u010648555/article/details/51612030
- SCNN车道线检测--(SCNN)Spatial As Deep: Spatial CNN for Traffic Scene Understanding(论文解读)
Spatial As Deep: Spatial CNN for Traffic Scene Understanding 收录:AAAI2018 (AAAI Conference on Artific ...
- dataview findrows
DataView dvStu = dsStu.Tables[0].Copy().DefaultView;//当前学年学期下所有学生 dvStu.Sort = "bjmc,xm"; ...
- WebApplicationContext类的作用
WebApplicationContext是实现ApplicationContext接口的子类.是专门为WEB应用准备的.作用: 1.它允许从相对于Web根目录的路径中加载配置文件完成初始化工作.从W ...
- Uncaught (in promise) TypeError:的错误
1.错误 创建一个vue实例,在data定义一些变量,如activityTime. 在methods里面用了axios发送请求. 在then的回调里使用this.activityTime 报错! 2. ...
- Django项目实战之用户头像上传与访问
1 将文件保存到服务器本地 upload.html <!DOCTYPE html> <html lang="en"> <head> < ...
- ionic安装教程
首先是安装node.js,通过nodejs官网下载,网址https://nodejs.org/en/.如果下载许要教程推荐这个https://www.cnblogs.com/zhouyu2017/p/ ...
- Docker 数据卷
数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性: 数据卷可以在容器之间共享和重用 对数据卷的修改会立马生效 对数据卷的更新,不会影响镜像 卷会一直存在,直到没有容 ...