1. 什么是延迟加载
-
在获取具有关联关系的表数据(订单表和用户表)时,首先加载主表信息(订单),对于关联表(用户)的信息只在真正需要访问的时候,才去数据库加载,称为延迟加载(也叫懒加载、按需加载)
-
在Mybatis中 只有association和collection支持延迟加载。
-
延迟加载的作用:提供性能
2. 延迟加载的相关设置
-
在Mybatis延迟加载默认是关闭状态的,使用延迟加载前,必须核心配置文件中打开延迟加载的总开关
<!-- 全局参数配置 --> <settings> <!-- 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 --> <setting name="logImpl" value="LOG4J"/> <!-- 开启延迟加载 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 将积极加载改为消极加载,也就是按需加载 --> <setting name="aggressiveLazyLoading" value="false"/> </settings>
3. 1:1关联的延迟加载
3.1 需求
- 根据订单ID获取订单信息(延迟加载关联的用户信息)
3.2 开发步骤
-
步骤1:添加接口方法
// Lazy loading : 懒加载 多对一 /** * 根据订单 id 查询订单、用户的信息 * @param id * @return */ public OrderExt getOrderAndUserLazyLoading(Integer id);
-
步骤2:添加sql映射
情况1:被延迟加载的关联表sql跟主表sql在同一个Mapper文件中<resultMap type="OrderExt" id="OrderAndUserLazyLoadingMap"> <!-- order属性 , 基础属性 --> <id column="id" property="id" /> <result column="user_id" property="user_id" /> <result column="number" property="number" /> <result column="createtime" property="createtime" /> <result column="note" property="note" /> <!-- 一方 , 多对一 --> <association property="user" javaType="User" select="findUserById" column="user_id"> </association> </resultMap> <!-- 根据 id 查询 Order --> <select id="getOrderAndUserLazyLoading" parameterType="int" resultMap="OrderAndUserLazyLoadingMap"> SELECT o.id, o.user_id, o.number, o.createtime, o.note FROM `order` o where o.id = #{id} </select> <!-- 根据 id 查找 User --> <select id="findUserById" parameterType="int" resultType="user"> select u.id, u.username, u.birthday, u.sex, u.address from `user` u where u.id = #{id} </select>
情况2:被延迟加载的关联表sql跟主表sql不在同一个Mapper文件中
Orders表->OrdersMapper.xml
Users表->UsersMapper.xml
-
-
操作1:添加UsersMapper.xml文件
<!-- 根据 id 查找 User --> <select id="findUserById" parameterType="int" resultType="user"> select u.id, u.username, u.birthday, u.sex, u.address from `user` u where u.id = #{id} </select>
-
-
-
操作2:在OrdersMapper.xml中引用 UsersMapper中的sql
<resultMap type="OrderExt" id="OrderAndUserLazyLoadingMap"> <!-- order属性 , 基础属性 --> <id column="id" property="id" /> <result column="user_id" property="user_id" /> <result column="number" property="number" /> <result column="createtime" property="createtime" /> <result column="note" property="note" /> <!-- 一方 , 多对一 --> <association property="user" javaType="User" select="com.hxzy.mapper.UserMapper.findUserById" column="user_id"> </association> </resultMap>
-
-
-
操作3:添加UsersMapper接口
/** * 根据 id 查找 用户对象 * @param id * @return */ public User findUserById(int id);
-
-
步骤3:测试
public class Test04 { private SqlSessionFactory sqlSessionFactory; @Before public void before() throws IOException { // MyBatis 配置文件路径 String resource = "mybatis-config.xml"; // 通过Resource 读取配置文件输入流 InputStream inputStream = Resources.getResourceAsStream(resource); // 创建SQL会话工厂 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void method01() throws IOException { SqlSession sqlSession = sqlSessionFactory.openSession(); OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); OrderExt orderExt = orderMapper.getOrderAndUserLazyLoading(1); System.out.println(orderExt); sqlSession.close(); } }
注意:Mybatis依赖版本太低会导致 Cause: java.lang.IllegalStateException: Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.
修改方法:提供版本
4. 1:n关联的延迟加载
4.1 需求
- 根据订单Id获取订单(延迟加载用户、订单明细)
4.2 开发步骤
-
步骤1:添加接口
public interface OrderMapper { // Lazy loading : 懒加载 多对一 /** * 根据订单 id 查询订单、用户的信息 * @param id * @return */ public OrderExt getOrderAndUserLazyLoading(Integer id); /** * 根据订单 id 查询订单、详单的信息 * @param id * @return */ public OrderExt getOrderDetailsByIdLazyLoading(Integer id); }
-
步骤2:添加sql映射
<!-- 一对多 --> <resultMap type="OrderExt" id="OrderAndDetailsLazyLoadingMap" extends="OrderAndUserLazyLoadingMap"> <collection property="orderDetails" select="getOrderDetailsById" column="id"></collection> </resultMap> <!-- 根据 id 查询 订单信息 --> <select id="getOrderDetailsByIdLazyLoading" parameterType="int" resultMap="OrderAndDetailsLazyLoadingMap"> SELECT o.id, o.user_id, o.number, o.createtime, o.note FROM `order` o where o.id = #{id} </select> <!-- 根据 订单 id 查询详单列表 --> <select id="getOrderDetailsById" parameterType="int" resultType="OrderDetail"> SELECT id,orders_id,items_id,items_num FROM orderdetail where orders_id = #{id} </select>
-
步骤3:测试
public class Test04 { private SqlSessionFactory sqlSessionFactory; @Before public void before() throws IOException { // MyBatis 配置文件路径 String resource = "mybatis-config.xml"; // 通过Resource 读取配置文件输入流 InputStream inputStream = Resources.getResourceAsStream(resource); // 创建SQL会话工厂 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void method02() throws IOException { SqlSession sqlSession = sqlSessionFactory.openSession(); OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); OrderExt orderExt = orderMapper.getOrderDetailsByIdLazyLoading(1); System.out.println(orderExt); sqlSession.close(); } }