定义
延迟加载或者也叫惰性加载,懒加载。使用延迟加载可以提高程序的运行效率。Java程序与数据库交互的频次越低,程序运行效率越高,所以我们应该尽量减少Java程序与数据库的交互次数,MyBatis延迟加载就很好的做到了这一点。
通过一个具体的业务场景来理解延迟加载:
班级(Classes)和学生(Student),当我们查询Student对象时,因为有级联关系,所以会将对应的Classes对象一并查询出来,这样就需要发送两条SQL语句,分别查询classes表和student表中的数据。
延迟加载的思路是:当我们查询Student的时候,如果没有调用classes属性,则只发送了一条SQL语句查询Student;如果需要调用classes属性,则发送两条SQL语句查询Student和Classes。所以延迟加载可以看做是一种优化机制,根据具体的代码,自动选择发送的SQL语句条数。
代码
接下来我们通过代码来实现延迟加载。
1.数据库建表。
classes表:
DROP TABLE IF EXISTS `classes`;
CREATE TABLE `classes` (
`c_id` int(11) NOT NULL AUTO_INCREMENT,
`c_name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`c_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
student表:
DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(11) DEFAULT NULL, `address` varchar(11) DEFAULT NULL, `tel` varchar(255) DEFAULT NULL, `score` double(11,1) DEFAULT NULL, `cid` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `tid` (`address`), KEY `cid` (`cid`), CONSTRAINT `student_ibfk_1` FOREIGN KEY (`cid`) REFERENCES `classes` (`c_id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
2.创建Classes实体类
package com.alice.entity;
@Data
public class Classes {
private int id;
private String name;
}
3.创建Student实体类
package com.alice.entity; @
Data
public class Student {
private int id;
private String name;
private String address;
private String tel;
private int score;
private Classes classes;
}
4.创建ClassesDAO
package com.alice.dao;
import com.southwind.entity.Classes;
public interface ClassesDAO {
public Classes getById(int id);
}
5.创建StudentDAO
package com.alice.dao;
import com.alice.entity.Student;
public interface StudentDAO {
public Student getById(int id);
}
6.创建ClassesDAO.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.alice.dao.ClassesDAO">
<resultMap type="classes" id="classesMap">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
</resultMap>
<select id="getById" parameterType="int" resultMap="classesMap">
select * from classes where c_id = #{id}
</select>
</mapper>
7.创建StudentDAO.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.alice.dao.StudentDAO">
<resultMap type="student" id="studentMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="address" column="address"/>
<result property="tel" column="tel"/>
<result property="score" column="score"/>
<association property="classes" javaType="classes" select="com.southwind.dao.ClassesDAO.getById" column="cid"></association>
</resultMap>
<select id="getById" parameterType="int" resultMap="studentMap">
select * from student where id = #{id}
</select>
</mapper>
8.查询Student,输出name。
package com.southwind.test;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.southwind.dao.StudentDAO;
import com.southwind.entity.Student;
public class Test {
public static void main(String[] args) {
InputStream is = Test.class.getClassLoader().getResourceAsStream("config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
Student student = studentDAO.getById(1);
System.out.println(student.getName());
}
}
可以看到,执行了两条SQL,分别查询出Student对象和级联的Classes对象,但是此时我们只需要输出Student的name,没有必要去查询Classes对象,开启延迟加载,即可解决这个问题。
9.config.xml中开启延迟加载
<?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 -->
<settings>
<!-- 打印SQL -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 将即时加载改为按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!-- 实体类设置别名 -->
<typeAliases>
<typeAlias type="com.alice.entity.Student" alias="student"/>
<typeAlias type="com.alice.entity.Classes" alias="classes"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/alice/dao/StudentDAO.xml"/>
</mappers>
</configuration>
10.再次查询Student,输出name,可以看到只打印了一条SQL语句,查询Student对象。
11.查询Student,输出级联Classes对象的name。
package com.southwind.test;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.southwind.dao.StudentDAO;
import com.southwind.entity.Student;
public class Test {
public static void main(String[] args) {
InputStream is = Test.class.getClassLoader().getResourceAsStream("config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
Student student = studentDAO.getById(1);
System.out.println(student.getClasses().getName());
}
}
可以看到执行了两条SQL,因为此时需要用到Student对象所级联的Classes对象,按需加载,所以在执行查询Student的SQL的同时,也需要执行查询Classes的SQL。
来源:oschina
链接:https://my.oschina.net/u/4411637/blog/4329630