分享

MyBatis教程(4):延迟加载

 太极混元天尊 2018-04-21


前言:


什么是延迟加载?


延迟加载或者也叫惰性加载,懒加载。使用延迟加载可以提高程序的运行效率。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。





    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约