InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = factory.openSession();
// IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);
// User user = mapper.findById(1);
User user = sqlSession.selectOne("com.lagou.mapper.IUserMapper.findById", 1);
//
System.out.println(user.getUsername());
System.out.println(user.getOrderList());
1. queryFromDatabase 数据库查询用户信息 select * from user where id = #{id}
2. createResultObject 创建响应对象User
3. getNestedQueryMappingValue 根据嵌套查询条件,直接利用当前的excutor去查询数据库的结果 select * from orders where uid = #{uid}
4. handleRowValuesForNestedResultMap 处理嵌套查询的结果
1. queryFromDatabase 数据库查询用户信息 select * from user where id = #{id}
2. createResultObject 创建响应对象,注意这个时候是利用javassit生成的是代理对象
源代码如下:
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
this.useConstructorMappings = false; // reset previous mapping result
final List> constructorArgTypes = new ArrayList<>();
final List
3 getNestedQueryMappingValue 在处理嵌套查询的值得时候,如果是懒加载,会先把这个查询的信息存起来,代码如下:
// 创建 ResultLoader 对象, 里面是查询相关的信息
final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
// 如果要求延迟加载,则延迟加载
if (propertyMapping.isLazy()) {
// 如果该属性配置了延迟加载, 注意这个lazyLoader和创建代理对象的是相同的
lazyLoader.addLoader(property, metaResultObject, resultLoader);
value = DEFERED;
// 如果不要求延迟加载,则直接执行加载对应的值
} else {
value = resultLoader.loadResult();
}
这里并不会对嵌套查询执行真正的查数据库操作,而是把嵌套查询相关的信息(执行器信息,配置信息,查询信息等)放在了lazyLoader,而这个lazyLoader正式创建代理对象的参数。(user对象里包含了懒加载的信息)
User user = sqlSession.selectOne(“com.lagou.mapper.IUserMapper.findById”, 1);
所以我们此时拿到的user是个代理对象,
在我们使用这个user对象的时候,实际走的是代理对象的invoke方法,
那么我们就需要看下他的invoke方法:
@Override
public Object invoke(Object enhanced, Method method, Method methodProxy, Object[] args) throws Throwable {
final String methodName = method.getName();
try {
synchronized (lazyLoader) {
if (WRITE_REPLACE_METHOD.equals(methodName)) {
Object original;
if (constructorArgTypes.isEmpty()) {
original = objectFactory.create(type);
} else {
original = objectFactory.create(type, constructorArgTypes, constructorArgs);
}
PropertyCopier.copyBeanProperties(type, enhanced, original);
if (lazyLoader.size() > 0) {
return new JavassistSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);
} else {
return original;
}
} else {
// 如果代理对象的存储了嵌套查询的信息
if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
lazyLoader.loadAll();
} else if (PropertyNamer.isSetter(methodName)) {
final String property = PropertyNamer.methodToProperty(methodName);
lazyLoader.remove(property);
// 如果调用了 get 方法,则执行延迟加载, 比如执行user.getOrder()
} else if (PropertyNamer.isGetter(methodName)) {
final String property = PropertyNamer.methodToProperty(methodName);
if (lazyLoader.hasLoader(property)) {
//查询数据库
lazyLoader.load(property);
}
}
}
}
}
// 继续执行原方法
return methodProxy.invoke(enhanced, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
}
所以在获取嵌套查询信息的时候user.getOrderList(),才会执行对应的sql。
所以懒加载利用了动态代理(感觉这玩意那块都有它), 如有错误, 感谢指正!