前言:
什么是延迟加载?
延迟加载或者也叫惰性加载,懒加载。使用延迟加载可以提高程序的运行效率。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.southwind.entity;
public class Classes { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return 'Classes [id=' + id + ', name=' + name + ']'; }
}
3.创建Student实体类
package com.southwind.entity;
public class Student { private int id; private String name; private String address; private String tel; private int score; private Classes classes; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } public Classes getClasses() { return classes; } public void setClasses(Classes classes) { this.classes = classes; } @Override public String toString() { return 'Student [id=' + id + ', name=' + name + ', address=' + address + ', tel=' + tel + ', score=' + score + ', classes=' + classes + ']'; }
}
4.创建ClassesDAO
package com.southwind.dao;
import com.southwind.entity.Classes;
public interface ClassesDAO { public Classes getById(int id); }
5.创建StudentDAO
package com.southwind.dao;
import com.southwind.entity.Student;
public interface StudentDAO { public Student getById(int id); }
6.创建ClassesDAO.xml
mapper namespace='com.southwind.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
mapper namespace='com.southwind.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中开启延迟加载
configuration>
settings> setting name='logImpl' value='STDOUT_LOGGING'/> setting name='lazyLoadingEnabled' value='true' /> setting name='aggressiveLazyLoading' value='false'/> settings>
typeAliases> typeAlias type='com.southwind.entity.Student' alias='student'/> typeAlias type='com.southwind.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/southwind/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。
|