Mybatis延迟加载

感情迁移 提交于 2020-08-08 14:30:43

 

定义

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

image.gifimage.png

 

可以看到,执行了两条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&amp;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对象。

image.png

 

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。

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!