【11】MyBatis 延迟加载

1. 什么是延迟加载

  • 在获取具有关联关系的表数据(订单表和用户表)时,首先加载主表信息(订单),对于关联表(用户)的信息只在真正需要访问的时候,才去数据库加载,称为延迟加载(也叫懒加载、按需加载)

  • 在Mybatis中 只有association和collection支持延迟加载。

  • 延迟加载的作用:提供性能

2. 延迟加载的相关设置

  • 在Mybatis延迟加载默认是关闭状态的,使用延迟加载前,必须核心配置文件中打开延迟加载的总开关
    【11】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();
      	}
      }   
    

【11】MyBatis 延迟加载
注意:Mybatis依赖版本太低会导致 Cause: java.lang.IllegalStateException: Cannot enable lazy loading because CGLIB is not available. Add CGLIB to your classpath.
修改方法:提供版本
【11】MyBatis 延迟加载

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();
      	}
     }   
    

【11】MyBatis 延迟加载