Mybatis延迟加载
在多表关联查询时,可以通过association加载关联方数据,例如通过findById加载指定Student后,继续对应的加载Classes数据。如果有一种需求,查询student时,只加载该student数据,只有需要加载对应的classes时,例如调用student.getClasses(),此时mybatis框架采取执行加载对应classes的操作,这就叫延迟加载。
延迟加载步骤
-
在config.xml中开启延迟加载
<settings> <!--打印日志--> <setting name="logImpl" value="STDOUT_LOGGING"/> <!--开启延迟加载--> <setting name="lazyLoadingEnabled" value="true"/> </settings>
-
将多表关联查询拆分成单表查询
-
ClassesRepository.java
package com.simon.app.repository; import com.simon.app.entity.Classes; public interface ClassesRepository { public Classes findById(long id); }
-
ClassesRepository.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.simon.app.repository.ClassesRepository"> <resultMap id="classesMap" type="com.simon.app.entity.Classes"> <id column="id" property="id"></id> <result column="name" property="name"></result> </resultMap> <select id="findById" parameterType="long" resultMap="classesMap"> select id,name from classes where id=#{id} </select> </mapper>
-
StudentRepository.java
package com.simon.app.repository; import com.simon.app.entity.Student; public interface StudentRepository { public Student findById(long id); }
-
StudentRepository.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.simon.app.repository.StudentRepository"> <resultMap id="studentMap" type="com.simon.app.entity.Student"> <id column="id" property="id"></id> <result column="name" property="name"></result> <association property="classes" javaType="com.simon.app.entity.Classes" select="com.simon.app.repository.ClassesRepository.findById" column="cid"> </association> </resultMap> <select id="findById" parameterType="long" resultMap="studentMap"> select id,name,cid from student where id=#{id} </select> </mapper>
- 第11行只是进行简单的student查询
- association标签中增加了select属性,也就是说student中的classes属性值是通过ClassesRepository接口的findById进行读取,而该findById的参数是通过column属性获取的,而值就是查询student的sql语句中的字段名
-
测试
package test; import com.simon.app.entity.Student; import com.simon.app.repository.StudentRepository; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.InputStream; public class Test { public static void main(String[] args) { InputStream resource = Test.class.getClassLoader().getResourceAsStream("config.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = sqlSessionFactoryBuilder.build(resource); SqlSession sqlSession = factory.openSession(); //获取接口的代理对象 StudentRepository mapper = sqlSession.getMapper(StudentRepository.class); Student student = mapper.findById(1L); System.out.println(student.getName()); sqlSession.close(); } }
执行后可以看到只加载了student部分,关联的classes为null,控制台上可以看见只发出了一条查询student的sql语句。
如果此时需要读取该student关联的classes,可以在20行后增加如下语句
System.out.println(student.getClasses());
执行后就会发现控制台连续发出了两条sql语句,延迟加载成功。
注意:平常习惯性的写下面的语句
System.out.println(student)
结果总是发出两条sql分别查询student和classes,还以为延迟加载失败了,其实也可以理解,因为直接打印student,肯定会发出查询关联的classes的命令,如果只显示student自身的属性就不会出现以上情况,所以要加以注意。
-