(三) - 懒加载
懒加载(也叫延时加载)将根据要查询的内容自动判断在查完一张表后直接返回结果还是继续去查其他表来返回结果, 从而避免浪费资源, 下面举例说明:
在一般情况下(即不使用懒加载), 我们可能会遇到一下情形:
Student.java:
public class Student { private long id; private String name; private long phoneNumber; private Country country; public long getId() { return id; } }
Country.java:
public class Country { private long cid; private String country; }
有两张表: student 和 country, 如果我们只需要查 student 的基本信息(名字, 号码等), 则只需要查 student 一张表就好了, 如果我们需要查到 student 的 country 相关信息, 则需要查两张表(先查 student 表, 获取到外键信息后去 country 表查到 country 信息, 本例中的外键指的是 student 中的 id ). 为了满足这样的需求, 我们需要两句 sql, 一般实现方式如下:
创建接口文件 DataRepository.java:
public interface DataRepository { public Student findStudent(long id); public Country findCountry(long id); }
创建配置文件 DataRepository.xml: (两句 sql, 分别查询 student 信息和 country 信息)
<?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.ryan.repository.DataRepository"> <resultMap id="findStudent" type="com.ryan.javaClass.Student"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="phoneNumber" property="phoneNumber"/> <association property="country" javaType="com.ryan.javaClass.Country"> <id column="cid" property="cid"/> <result column="country" property="country"/> </association> </resultMap> <select id="findStudent" parameterType="long" resultMap="findStudent"> select * from student where id=#{id}; </select> <resultMap id="findCountry" type="com.ryan.javaClass.Country"> <id column="id" property="cid"/> <result column="country" property="country"/> </resultMap> <select id="findCountry" parameterType="long" resultMap="findCountry"> select * from country where id=#{cid}; </select> </mapper>
测试:
public class Test1 { public static void main(String[] args) { InputStream inputStream = DataRepository.class.getClassLoader().getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); //获取实现接口的代理对象 DataRepository dataRepository = sqlSession.getMapper(DataRepository.class); //获取 student 信息 Student student = dataRepository.findStudent(4399); System.out.println(student); // sqlSession.close(); //获取 country 信息, 需要在获取上一次查询结果的基础上再次查询 Country country = dataRepository.findCountry(student.getId()); System.out.println(country); sqlSession.close(); } }
结果:
如上例, 我们需要多句 sql 来查询相关信息.
但使用了懒加载, 则使用一句 sql 就可以了, 具体操作如下:
首先, 修改配置文件如下: 修改 student 的 resultMap, 在 association 标签中添加 select 属性, 值为查询 country 的接口方法, 添加 column 属性, 值为查询 country 的条件, 这句话可以这么理解: 当触发懒加载时, 用 select 中的方法和 column 中的条件进行查询, 将查到的结果集作为对象的 property 属性注入到对象中 (association 中也不用再指定属性了, 因为会调用 select 中的方法去指定).
<?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.ryan.repository.DataRepository"> <resultMap id="findStudent" type="com.ryan.javaClass.Student"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="phoneNumber" property="phoneNumber"/> <association property="country" javaType="com.ryan.javaClass.Country" select="com.ryan.repository.DataRepository.findCountry" column="id"/> </resultMap> <select id="findStudent" parameterType="long" resultMap="findStudent"> select * from student where id=#{id}; </select> <resultMap id="findCountry" type="com.ryan.javaClass.Country"> <id column="id" property="cid"/> <result column="country" property="country"/> </resultMap> <select id="findCountry" parameterType="long" resultMap="findCountry"> select * from country where id=#{cid}; </select> </mapper>
然后需要在 mybatis 的配置文件中开启懒加载, (同时打开显示 sql 执行过程的开关, 方便查看 sql 的执行细节):
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!--打印SQL--> <setting name="logImpl" value="STDOUT_LOGGING"/> <!--开启延时加载/懒加载--> <setting name="lazyLoadingEnabled" value="true"/> </settings> <!--配置MyBatis运行环境--> <environments default="development"> <environment id="development"> <!--配置JDBC的事务管理--> ...
由此, 便可以使用懒加载了, 可以如下演示:
如果只要查询 student 的 name, 则只需执行一次 sql:
如果需要查询 student 的 country, 则需执行两次 sql:
可见, 操作上是相同的调用方法的操作, 但具体要执行一次 sql 还是多次, 程序将自己判断, 从而节省了资源.