介绍
该笔记是在学习拉勾教育 Java 高薪训练营后,结合课程和老师的视频,自己跟踪源码后做的笔记。
MyBatis 的延迟加载
MyBatis 是支持延迟加载,又叫懒加载。先查询主要信息,在按需去查询其他信息。即需要时加载查询,不需要时就不加载查询。使用延迟加载的目的是减轻数据库的压力,只有需要时才去查询。
举例,如下没使用延迟加载的话,就会两张表都查询,查出 orders 和 users 的信息,在拼接成一块。
SELECT orders.*, users.username FROM orders, users WHERE orders.user_id = users.id
-- 延迟加载相当于如下执行
SELECT orders.*,
(SELECT username FROM USER WHERE orders.user_id = user.id)username FROM orders
使用延迟加载的话,会先从单表查询,在去关联表查询, 这里将多表查询分为两次单表查询,不是一次性查所有,能提高数据库性能。
- 先查询单表 orders,会查出 orders.user_id;
- 在根据 orders.user_id 去 users 表中查询。
延迟加载原理
延迟加载是通过动态代理来实现的,在 MyBatis 有两种,分别为 javassist 和 cglib。以 javassist 为例,分为两步。
创建动态代理对象
假设有一个 Order 对象,包含订单信息 orderId、money 和一个用户对象(信息),要查询订单信息和用户信息,如下代码。
- 在 for 循环中会执行 propertyMapping.isLazy() 判断是否为懒加载。在 xml 中关于懒加载的标签是 association 和 collection,分析这两个标签即可。同时还要满足 select,只有查询才有懒加载;
- configuration.getProxyFactory().createProxy(),当为懒加载时,会创建一个动态代理对象 resultObject,保存相关参数和 SQL,替换掉原先的映射后的结果对象。
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
// useConstructorMappings ,表示是否使用构造方法创建该结果对象。此处将其重置
this.useConstructorMappings = false; // reset previous mapping result
final List<Class<?