Mybatis的延迟加载

夙愿已清 提交于 2019-12-28 02:41:29

在实际开发中,有的数据不需要立即加载,而是需要的时候再去加载,不需要用到的时候则不去加载,这就是延时加载,也称为按需加载(懒加载)

  • 利 : 提高数据库性能 
    弊 : 需要时候在查询,存在大批量的数据查询。
    

assocation的延时加载

要求:查询账户信息,同时按需加载用户信息。

  1. 创建实体类
package com.liang.domain;

import java.io.Serializable;

/**
 * 账户实体类
 */
public class Account implements Serializable {

    private int id;
    private int uid;
    private Double money;

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", uid=" + uid +
                ", money=" + money +
                '}';
    }
}
package com.liang.domain;

import java.util.Date;

/**
 * 用户类
 */
public class User {

    private int id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
  1. 创建持久层接口
package com.liang.dao;

import com.liang.domain.Account;

import java.util.List;

/**
 * 账户的持久层接口
 */
public interface AccountDao {

    /**
     * 查询所有账户信息,同时包含其用户信息
     * @return
     */
    List<Account> findAll();
}
package com.liang.dao;

public interface UserDao{

  /**
     * 根据id查询用户
     * @param id
     * @return
     */
    User findById(int id);
}
  1. 编写持久层映射文件
 <resultMap id="accountMap" type="com.liang.domain.Account">
        <id property="id" column="id"></id>
        <result column="uid" property="uid"></result>
        <result column="money" property="money"></result>
        <!--建立Account类中user属性对应的数据库表
        column:	数据库中的列名,或者是列的别名。一般情况下,是我们传递给select映射的参数
        select: 用于加载复杂类型属性的映射语句的 ID,它会从 column 属性指定的列中检索数据,作为参数传递给目标 select 语句。
        -->
        <association property="user" javaType="com.liang.domain.User" select="com.liang.dao.UserDao.findById" column="uid">
        </association>
    </resultMap>
    <!--查询所有账户信息,同时包含其用户信息-->
    <select id="findAll" resultMap="accountMap">
       select *from account;
    </select>
   <!--根据id查询用户-->
    <select id="findById" resultType="User" parameterType="int">
        <include refid="querySql"></include> where id= #{userID};
    </select>
  1. 编写测试方法
   /**
     * 查询所有账户信息,同时包含其用户信息【延迟加载】
     */
    @Test
    public void testFindAll()
    {
        List<Account> accounts = accountDao.findAll();
    }
  1. 开启延迟加载策略
  <settings>
        <!--
            lazyLoadingEnabled : 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
            aggressiveLazyLoading : 当开启时,任何方法的调用都会加载该对象的所有属性
        -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

此时执行程序的日志为:
在这里插入图片描述
而当没有延时加载时,程序执行日志为:
在这里插入图片描述
可以看出:当没有延时加载时候,采用的是立即加载策略。

collection的延时加载

要求:查询用户信息,同时按需加载账户信息。

  1. 编写实体类
package com.liang.domain;

import java.util.Date;
import java.util.List;

/**
 * 用户类
 */
public class User {

    private int id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    private List<Account> accounts;

    public List<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
package com.liang.domain;

import java.io.Serializable;

/**
 * 账户实体类
 */
public class Account implements Serializable {

    private int id;
    private int uid;
    private Double money;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", uid=" + uid +
                ", money=" + money +
                '}';
    }
}
  1. 编写持久层接口类方法
package com.liang.dao;

import com.liang.domain.User;

import java.util.List;

public interface UserDao{


    /**
     * 查询所有用户
     * @return
     */
    List<User> findAll();

}
package com.liang.dao;

import com.liang.domain.Account;

import java.util.List;

/**
 * 账户的持久层接口
 */
public interface AccountDao {

    /**
     * 通过用户id查询账户信息
     * @param uid
     * @return
     */
    List<Account> findByUid(int uid);
}
  1. 编写持久层映射文件
<?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.liang.dao.UserDao">

    <resultMap id="userMap" type="com.liang.domain.User">
        <id column="id" property="id"></id>
        <result property="username" column="username"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
        <result property="birthday" column="birthday"></result>
        <collection property="accounts" select="com.liang.dao.AccountDao.findByUid" column="id"></collection>
    </resultMap>
    <select id="findAll" resultMap="userMap">
            select *from user;
    </select>
</mapper>
<?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.liang.dao.AccountDao">

    <select id="findByUid" parameterType="int" resultType="com.liang.domain.Account">
        select *from account where uid = #{uid}
    </select>

</mapper>
  1. 编写测试方法
import com.liang.dao.UserDao;
import com.liang.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestMyBatis {

    private SqlSession sqlSession = null;
    private InputStream inputStream = null;
    private UserDao userDao = null;

    @Before
    public void init() throws IOException {
        inputStream = Resources.getResourceAsStream("SqlConfig.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        sqlSession = sqlSessionFactory.openSession();
        userDao = sqlSession.getMapper(UserDao.class);
    }

    @After
    public void destroy() throws IOException {

        sqlSession.commit();

        sqlSession.close();
        inputStream.close();
    }

    /**
     * 查询所有用户信息
     */
    @Test
    public void testFindAll() {
        List<User> users = userDao.findAll();
    } 
}
  1. 开启延迟加载策略
  <settings>
        <!--
            lazyLoadingEnabled : 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
            aggressiveLazyLoading : 当开启时,任何方法的调用都会加载该对象的所有属性
        -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

经测试,开启延时加载时,程序执行日志为:
在这里插入图片描述

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