mybatis延迟加载、缓存

目录

一、所需表

二、延迟加载

1.延迟加载概念

2.立即加载和延迟加载的应用场景

3.多对一延迟加载查询演示

(1)实体类

User

Account

(2)AccountMapper接口

(3)AccountMapper.xml

(4)UserMapper接口

(5)UserMapper.xml

(6)在总配置文件(mybatis-config.xml)中开启延迟加载配置

(7)测试类

(8)运行

(9)如果测试类中的输出语句改为

4.一对多延迟加载

(1)实体类

(2)UserMapper接口

(3)UserMapper.xml文件

(4)AccountMapper接口

(5)AccountMapper.xml文件

(6)在总配置文件中开启延迟加载

(7)测试类

(8)运行

三、mybatis框架的缓存

1.概念

2.一级缓存

(1)验证一级缓存的存在

测试类

运行

(2)一级缓存失效的四种情况

①使用不同的sqlSession对象查询

测试类

运行

②使用相同的sqlSession对象进行查询,但是查询条件不同

测试类

运行

③使用相同的sqlSession对象进行查询,但是在两次执行中间我们进行了一次增删改操作

UserMapper接口

UserMapper.xml

测试类

运行

④使用相同的sqlSession对象进行查询,但是手动清除了缓存

测试类

运行

3.二级缓存

(1)在总配置文件中开启二级缓存

(2)在映射配置文件中配置

(3)实体类实现序列化接口

(4)二级缓存必须在SqlSession关闭或提交之后

(5)证明二级缓存

测试类

运行:


一、所需表

account

user

二、延迟加载

1.延迟加载概念

立即加载:当前查询用户的时候,默认把该用户所拥有的账户信息查询出来了

延迟加载:当前查询用户的时候,没有把该用户所拥有的账户信息查询出来,而是使用账户数据的时候,再去查询账户的数据

2.立即加载和延迟加载的应用场景

(1)查询账户的时候,可以直接把用户查询出来(多对一),这个时候可以选择立即加载

(2)查询用户的时候,可以先不查账户信息,需要账户信息的时候再去查,这时选择延迟加载

3.多对一延迟加载查询演示

(1)实体类

User
java 复制代码
package com.qcby.pojo;

import java.util.Date;

/*
* 一
* */
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    public User() {
    }

    public User(Integer id, String username, Date birthday, String sex, String address) {
        this.id = id;
        this.username = username;
        this.birthday = birthday;
        this.sex = sex;
        this.address = address;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer 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 + '\'' +
                '}';
    }
}
Account
java 复制代码
package com.qcby.pojo;

/*
* 多
* */
public class Account {
    private Integer id;
    private String money;
    private Integer uid;

    //多对一
    private User user;

    public Account() {
    }

    public Account(Integer id, String money, Integer uid, User user) {
        this.id = id;
        this.money = money;
        this.uid = uid;
        this.user = user;
    }

    public Integer getUid() {
        return uid;
    }

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

    public User getUser() {
        return user;
    }

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

    public Integer getId() {
        return id;
    }

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

    public String getMoney() {
        return money;
    }

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

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", money='" + money + '\'' +
                ", uid=" + uid +
                ", user=" + user +
                '}';
    }
}

(2)AccountMapper接口

java 复制代码
package com.qcby.mapper;

import com.qcby.pojo.Account;

import java.util.List;

public interface AccountMapper {
    
    /*
    * 多对一:
    * 查询所有
    * */
    public List<Account> findAll();
}

(3)AccountMapper.xml

在 <association> 标签中,需要指定一个 column 属性,这个属性的值应该是 account 表中用来关联 user 表的外键列名: column="uid"

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.qcby.mapper.AccountMapper"> <!--对谁进行操作就写谁-->

    <!--多对一:-->
    <!--查询所有:public List<Account> findAll();-->
    <select id="findAll" resultMap="accountMap">
        select * from account
    </select>
    <resultMap id="accountMap" type="account">
        <id property="id" column="id"/>
        <result property="money" column="money"/>
        <result property="uid" column="uid"/>
        <!--配置延迟加载-->
        <association property="user" column="uid" javaType="user" select="com.qcby.mapper.UserMapper.findById">
            <id column="id" property="uid"/>
            <result column="username" property="username"/>
            <result column="birthday" property="birthday"/>
            <result column="sex" property="sex"/>
            <result column="address" property="address"/>
        </association>
    </resultMap>
</mapper>

(4)UserMapper接口

java 复制代码
package com.qcby.mapper;

import com.qcby.pojo.User;

public interface UserMapper {
    
    /*
    * 多对一:
    * 根据id查询
    * */
    public User findById(Integer id);
}

(5)UserMapper.xml

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.qcby.mapper.UserMapper"> <!--对谁进行操作就写谁-->

    <!--多对一-->
    <!--根据id查询:public User findById(Integer id);-->
    <select id="findById" parameterType="int" resultType="user">
        select * from user where id=#{id}
    </select>
</mapper>

(6)在总配置文件(mybatis-config.xml)中开启延迟加载配置

mybatis-config.xml

XML 复制代码
<settings>
    <!--开启延迟加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--将积极加载改为消极加载及按需加载-->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

(7)测试类

java 复制代码
package com.qcby.test;

import com.qcby.mapper.AccountMapper;
import com.qcby.mapper.UserMapper;
import com.qcby.pojo.Account;
import com.qcby.pojo.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.ArrayList;
import java.util.List;

public class demo {
    private InputStream inputStream;
    private SqlSession sqlSession;
    private AccountMapper accountMapper;
    private UserMapper userMapper;
    @Before
    public void init() throws IOException {
        //加载配置文件
        inputStream= Resources.getResourceAsStream("mybatis-config.xml");
        //创建工厂对象
        SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
        //创建session对象
        sqlSession=sqlSessionFactory.openSession();
        //获取到代理对象
        userMapper=sqlSession.getMapper(UserMapper.class);
        accountMapper=sqlSession.getMapper(AccountMapper.class);
    }

    /*
    * 多对一:
    * account查询所有
    * */
    @Test
    public void findAllTest(){
        List<Account> accounts=accountMapper.findAll();
        for (Account account:accounts){
            //System.out.println("开始...");
            System.out.println(account.getMoney());
            //System.out.println("结束...");
            System.out.println("--------------------");
        }
    }




    @After
    public void destory() throws IOException {
        inputStream.close();
        sqlSession.close();
    }
}

(8)运行

可以看到此时是没有加载出来用户的信息的

(9)如果测试类中的输出语句改为

System.out.println(account.getUser().getUsername());

再运行:

可以看到此时执行了user根据id查询的sql语句

4.一对多延迟加载

(1)实体类

User类

java 复制代码
package com.qcby.pojo;

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

/*
* 一
* */
public class User {
    private Integer 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 Integer getId() {
        return id;
    }

    public void setId(Integer 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 + '\'' +
                ", accounts=" + accounts +
                '}';
    }
}

(2)UserMapper接口

java 复制代码
/*
* 一对多:
* 查询所有
* */
public List<User> findUserAll();

(3)UserMapper.xml文件

XML 复制代码
<!--一对多-->
<!--查询所有:public List<User> findUserAll();-->
<select id="findUserAll" resultMap="userMap">
    select * from user
</select>
<resultMap id="userMap" type="user">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="birthday" column="birthday"/>
    <result property="sex" column="sex"/>
    <result property="address" column="address"/>
    <collection property="accounts" column="id" ofType="account" select="com.qcby.mapper.AccountMapper.findAccountById">
        <id column="id" property="id"/>
        <result column="money" property="money"/>
        <result column="uid" property="uid"/>
    </collection>
</resultMap>

(4)AccountMapper接口

java 复制代码
/*
* 一对多:
* 根据id查询
* */
public Account findAccountById(Integer id);

(5)AccountMapper.xml文件

XML 复制代码
<!--一对多-->
<!--根据id查询:public Account findAccountById(Integer id);-->
<select id="findAccountById" parameterType="int" resultType="account">
    select * from account where id=#{id}
</select>

(6)在总配置文件中开启延迟加载

XML 复制代码
<settings>
    <!--开启延迟加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--将积极加载改为消极加载及按需加载-->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

(7)测试类

java 复制代码
/*
* 一对多:
* user查询所有
* */
@Test
public void findUserAllTest(){
    List<User> users=userMapper.findUserAll();
    for (User user:users){
        System.out.println(user.getUsername()+"  "+user.getAddress());
        System.out.println("--------------------");
    }
}

(8)运行

三、mybatis框架的缓存

1.概念

经常需要查询,不需要修改的数据,不特别重要的数据都可以存储到缓存中

2.一级缓存

①mybatis的一级缓存是SqlSession的缓存

②查询的时候,先从SqlSession的缓存中查找,如果有,直接返回,如果没有,再去查询数据库

(1)验证一级缓存的存在

查询两次,查看结果

查询的语句在多对一查询的时候写过了

测试类
java 复制代码
/*
* 验证一级缓存的存在
* */
@Test
public void findUserByIdTest(){
    User user1=userMapper.findById(1);
    System.out.println(user1);
    User user2=userMapper.findById(1);
    System.out.println(user2);
}
运行

(2)一级缓存失效的四种情况

①使用不同的sqlSession对象查询
测试类
java 复制代码
package com.qcby.test;

import com.qcby.mapper.AccountMapper;
import com.qcby.mapper.UserMapper;
import com.qcby.pojo.Account;
import com.qcby.pojo.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.ArrayList;
import java.util.List;

public class demo {
    private InputStream inputStream;
    private SqlSession sqlSession;
    private SqlSession sqlSession2;
    private AccountMapper accountMapper;
    private UserMapper userMapper;
    private UserMapper userMapper2;
    @Before
    public void init() throws IOException {
        //加载配置文件
        inputStream= Resources.getResourceAsStream("mybatis-config.xml");
        //创建工厂对象
        SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
        //创建session对象
        sqlSession=sqlSessionFactory.openSession();
        sqlSession2=sqlSessionFactory.openSession();
        //获取到代理对象
        userMapper=sqlSession.getMapper(UserMapper.class);
        userMapper2=sqlSession2.getMapper(UserMapper.class);
        accountMapper=sqlSession.getMapper(AccountMapper.class);
    }

 

    /*
     * 一级缓存失效的四种情况:
     * 1.使用不同的sqlSession对象进行查询
     * */
    @Test
    public void findUserByIdTest1(){
        User user1=userMapper.findById(1);
        System.out.println(user1);
        User user2=userMapper2.findById(1);
        System.out.println(user2);
    }

    @After
    public void destory() throws IOException {
        inputStream.close();
        sqlSession.close();
    }
}
运行
②使用相同的sqlSession对象进行查询,但是查询条件不同
测试类
java 复制代码
/*
 * 一级缓存失效的四种情况:
 * 2.使用相同的sqlSession对象进行查询,但是查询条件不同
 * */
@Test
public void findUserByIdTest2(){
    User user1=userMapper.findById(1);
    System.out.println(user1);
    User user2=userMapper.findById(2);
    System.out.println(user2);
}
运行
③使用相同的sqlSession对象进行查询,但是在两次执行中间我们进行了一次增删改操作
UserMapper接口
java 复制代码
/*
* 根据id删除
* */
public int deleteById(Integer id);
UserMapper.xml
XML 复制代码
<!--根据id删除:public int deleteById(Integer id);-->
<delete id="deleteById" parameterType="int">
    delete from user where id=#{id}
</delete>
测试类
java 复制代码
/*
 * 一级缓存失效的四种情况:
 * 3.使用相同的sqlSession对象进行查询,但是在两次执行中间我们进行了一次增删改操作
 * */
@Test
public void findUserByIdTest3(){
    User user1= userMapper.findById(1);
    System.out.println(user1);
    userMapper.deleteById(3);
    sqlSession.commit();
    User user2=userMapper.findById(1);
    System.out.println(user2);
}
运行
④使用相同的sqlSession对象进行查询,但是手动清除了缓存
测试类
java 复制代码
/*
 * 一级缓存失效的四种情况:
 *  4.使用相同的sqlSession对象进行查询,但是手动清除了缓存
 * */
@Test
public void findUserByIdTest4(){
    User user1=userMapper.findById(1);
    System.out.println(user1);
    sqlSession.clearCache();//手动清理缓存
    User user2=userMapper.findById(1);
    System.out.println(user2);
}
运行

3.二级缓存

二级缓存是SqlSessionFactory级别的

(1)在总配置文件中开启二级缓存

XML 复制代码
<!--开启二级缓存-->
<settings>
    <setting name="cacheEnabled" value="true"/>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

(2)在映射配置文件中配置<cache>

(3)实体类实现序列化接口

(4)二级缓存必须在SqlSession关闭或提交之后

(5)证明二级缓存

二级缓存的适用对象地址不同,但是也从缓存加载,二级缓存存储的是零散数据,是组装出来的对象

测试类
java 复制代码
package com.qcby.test;

import com.qcby.mapper.UserMapper;
import com.qcby.pojo.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.Test;

import java.io.IOException;
import java.io.InputStream;

public class demo2 {

    @Test
    public void test() throws IOException {
        //加载配置文件
        InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
        //创建工厂对象
        SqlSessionFactory sqlSessionFactory=new     SqlSessionFactoryBuilder().build(inputStream);

        //创建session对象
        SqlSession sqlSession1=sqlSessionFactory.openSession();
        //获取到代理对象
        UserMapper userMapper1=sqlSession1.getMapper(UserMapper.class);
        //调用方法
        User user1=userMapper1.findById(1);
        System.out.println(user1);
        System.out.println("-----------");
        //手动清理缓存
        sqlSession1.clearCache();
        sqlSession1.commit();
        sqlSession1.close();


        SqlSession sqlSession2=sqlSessionFactory.openSession();
        UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);
        User user2=userMapper2.findById(1);
        System.out.println(user2);
        sqlSession2.close();
        inputStream.close();

    }
}
运行:

可以看出,sql语句只执行了一次,说明它是查的缓存,但是地址不一样,因为他从缓存里组装出来的

相关推荐
m0_748256781 小时前
springboot整合mybatis-plus【详细版】
spring boot·tomcat·mybatis
lfl183261621602 小时前
清除前端缓存的方式
缓存
Y编程小白3 小时前
MyBatis-Plus6--MyBatis中的分页插件
java·开发语言·mybatis·mybatis-plus
m0_548514773 小时前
Spring Boot 集成MyBatis-Plus
spring boot·后端·mybatis
中科三方3 小时前
什么是DNS缓存?DNS缓存有什么用?
缓存
牛马程序员‍3 小时前
【云岚到家】-day03-门户缓存方案选择
redis·缓存·redistemplate·springcache
牛马程序员‍3 小时前
【云岚到家】-day03-门户缓存实现实战
缓存·wpf·cache·xxl-job·定时任务
会code的厨子3 小时前
MyBatis基于XML的详细使用-缓存
java·mybatis
!!!52513 小时前
MyBatis-增删改查操作&一些细节
java·数据库·spring boot·mybatis