MyBatis延迟加载
文章目录
- 1. 延迟加载的定义
- 2. 延迟加载的原理
- 3. 延迟加载的方式
- 直接加载
- 侵入式延迟加载
- 深度延迟加载
- 总结
1. 延迟加载的定义
延迟加载是MyBatis中一种按需查询的机制。当执行主查询获取到主对象后,对于主对象中的关联对象,并不会立即执行关联查询,而是在真正访问关联对象时才会触发对应的SQL语句进行查询。
这种机制的核心思想是"用时再取"。比如查询一个用户信息时,如果该用户关联了多个订单,延迟加载不会立即查询出所有订单数据,而是等到代码中真正调用获取订单列表的方法时,才会执行查询订单的SQL语句。
好处:
延迟加载能够有效避免不必要的数据库查询,减少数据库的负载压力,提高应用程序的整体性能。特别是在处理大量数据或者复杂关联关系时,延迟加载能够显著优化查询效率。
2. 延迟加载的原理
MyBatis的延迟加载基于动态代理技术实现。当MyBatis执行主查询创建结果对象时,会判断是否需要进行延迟加载。如果需要延迟加载,MyBatis会为该对象创建一个代理对象,而不是直接返回原始对象。这个代理对象会拦截对关联属性的访问操作。当程序代码访问需要延迟加载的属性时,代理对象会检测到这个调用,然后执行以下步骤:
- 首先,代理对象会根据配置的select语句和column参数,构造对应的SQL查询。
- 然后,代理对象会使用原始的SqlSession执行这个SQL查询,获取关联数据。
- 接着,将查询结果设置到目标属性中,最后返回查询到的数据给调用方。
3. 延迟加载的方式
MyBatis中的延迟加载根据加载时机和触发条件的不同,可以分为三种主要方式:
直接加载
直接加载是指在执行主查询的同时立即执行关联查询,一次性获取所有相关数据。这种方式不存在延迟,所有数据在第一次查询时就全部加载完成。
侵入式延迟加载
侵入式延迟加载是指当访问主对象的任意属性时,都会触发所有延迟加载属性的查询。这种方式对主对象的访问比较"敏感",只要触碰到对象就会加载所有关联数据。
<configuration><settings><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="true"/></settings>
</configuration>
当aggressiveLazyLoading设置为true时,启用侵入式延迟加载。在这种模式下,如果访问了主对象的任何属性(包括调用toString()、equals()等方法),MyBatis会立即加载该对象所有配置了延迟加载的关联属性。
Order order = orderMapper.selectById(1);
System.out.println(order.getOrderNo()); // 这行代码会触发所有延迟加载
深度延迟加载
深度延迟加载是最精确的延迟加载方式,只有在真正访问某个特定的关联属性时,才会触发该属性对应的查询。这种方式提供了最细粒度的控制。
<configuration><settings><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/><setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode"/></settings>
</configuration>
当aggressiveLazyLoading设置为false时,启用深度延迟加载。在这种模式下,只有直接访问关联属性时才会触发对应的查询。lazyLoadTriggerMethods用于指定哪些方法调用会触发延迟加载。
<resultMap id="UserResultMap" type="User"><id column="id" property="id"/><result column="username" property="username"/><collection property="orders" select="com.example.mapper.OrderMapper.selectByUserId"column="id" fetchType="lazy"/>
</resultMap>
使用示例:
User user = userMapper.selectById(1);
System.out.println(user.getUsername()); // 不会触发订单查询
System.out.println(user.getId()); // 不会触发订单查询List<Order> orders = user.getOrders(); // 只有这行代码才会触发订单查询
深度延迟加载是最常用的方式,避免了不必要的数据库查询,同时保持了代码的清晰性。
总结
MyBatis延迟加载是一种重要的性能优化机制,通过按需查询的方式减少数据库访问压力。延迟加载基于动态代理技术实现,当访问关联属性时才触发相应的SQL查询。根据触发条件和加载时机的不同,延迟加载分为三种方式:直接加载在主查询时立即获取所有数据,侵入式延迟加载在访问主对象任意属性时触发所有关联查询,而深度延迟加载只在访问特定关联属性时触发对应查询。