mybatis-查询延迟加载功能
SqlSession.getMapper ->
configuration.getMapper ->
mapperRegistry.getMapper ->
mapperProxyFactory.newInstance 返回mapper的代理对象 mapperProxy, 接口的查询、更新等方法通过动态代理技术由mapperProxy来代理执行。
mapperProxy.invoke ->
mapperMethod.execute -> 根据不同的sql类型执行 INSERT,UPDATE,DELETE,SELECT,FLUSH
SELECT : sqlSession.selectList - >
configuration.getMappedStatement ->
cachingExecutor.query -> 实际上委托 baseExecutor来执行的查询默认开启一级缓存,当开启 二级缓存的时候可以缓存查询结果
baseExecutor.queryFromDatabase- >
RoutingStatementHandler.query -> 通过 configuration.newStatementHandler获得
DefaultResultSetHandler.handleResultSets -> 获取 mapperStatement即xml里定义的resultMap标签,根据resultMap组装查询返回结果,如果接口方法中没有ResultHandler参数,则使用DefaultResultHandler来处理结果
1 private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException { 2 final ResultLoaderMap lazyLoader = new ResultLoaderMap(); 3 //创建结果对象,如果有延迟加载的属性,则创建代理对象 4 Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null); 5 if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { 6 final MetaObject metaObject = configuration.newMetaObject(rowValue); 7 boolean foundValues = this.useConstructorMappings; 8 //自动映射结果对象属性,当XML里没有定义的时候也能自动映射 9 if (shouldApplyAutomaticMappings(resultMap, false)) { 10 foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues; 11 } 12 //有属性需要延迟加载的时候,调用lazyLoader.addLoader添加 延迟加载器 13 foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues; 14 foundValues = lazyLoader.size() > 0 || foundValues; 15 rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null; 16 } 17 return rowValue; 18 }
1 //查询嵌套的resultMap属性值 2 private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) 3 throws SQLException { 4 final String nestedQueryId = propertyMapping.getNestedQueryId(); 5 final String property = propertyMapping.getProperty(); 6 final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId); 7 final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType(); 8 final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix); 9 Object value = null; 10 if (nestedQueryParameterObject != null) { 11 final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject); 12 final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql); 13 final Class<?> targetType = propertyMapping.getJavaType(); 14 if (executor.isCached(nestedQuery, key)) { 15 executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType); 16 value = DEFERED; 17 } else { 18 final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql); 19 //添加属性延迟加载器!!!! 20 if (propertyMapping.isLazy()) { 21 lazyLoader.addLoader(property, metaResultObject, resultLoader); 22 value = DEFERED; 23 } else { 24 value = resultLoader.loadResult(); 25 } 26 } 27 } 28 return value; 29 }
当返回结果对象查询延迟属性的时候触发动态代理
1 @Override 2 public Object invoke(Object enhanced, Method method, Method methodProxy, Object[] args) throws Throwable { 3 final String methodName = method.getName(); 4 try { 5 synchronized (lazyLoader) { 6 if (WRITE_REPLACE_METHOD.equals(methodName)) { 7 Object original; 8 if (constructorArgTypes.isEmpty()) { 9 original = objectFactory.create(type); 10 } else { 11 original = objectFactory.create(type, constructorArgTypes, constructorArgs); 12 } 13 PropertyCopier.copyBeanProperties(type, enhanced, original); 14 if (lazyLoader.size() > 0) { 15 return new JavassistSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs); 16 } else { 17 return original; 18 } 19 } else { 20 //当查询的属性为延迟加载的属性时,LazyHolder 21 进行延迟加载 22 if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) { 23 if (aggressive || lazyLoadTriggerMethods.contains(methodName)) { 24 lazyLoader.loadAll(); 25 } else if (PropertyNamer.isSetter(methodName)) { 26 final String property = PropertyNamer.methodToProperty(methodName); 27 lazyLoader.remove(property); 28 } else if (PropertyNamer.isGetter(methodName)) { 29 final String property = PropertyNamer.methodToProperty(methodName); 30 if (lazyLoader.hasLoader(property)) { 31 //延迟加载 32 lazyLoader.load(property); 33 } 34 } 35 } 36 } 37 } 38 return methodProxy.invoke(enhanced, args); 39 } catch (Throwable t) { 40 throw ExceptionUtil.unwrapThrowable(t); 41 } 42 } 43 }
至此,延迟加载逻辑结束!!