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语句只执行了一次,说明它是查的缓存,但是地址不一样,因为他从缓存里组装出来的

相关推荐
qhd吴飞1 小时前
mybatis 差异更新法
java·前端·mybatis
小王子10244 小时前
Django缓存机制详解:从配置到实战应用
redis·缓存·django·rbac
Antonio9155 小时前
【Redis】Redis 数据存储原理和结构
数据库·redis·缓存
追风少年浪子彦6 小时前
mybatis-plus实体类主键生成策略
java·数据库·spring·mybatis·mybatis-plus
problc6 小时前
大模型API和秘钥获取地址
数据库·redis·缓存
Rover.x7 小时前
内存泄漏问题排查
java·linux·服务器·缓存
木宇(记得热爱生活)8 小时前
Qt GUI缓存实现
开发语言·qt·缓存
开往19829 小时前
spring boot整合mybatis
java·spring boot·mybatis
guojl9 小时前
MyBatis应用案例
后端·mybatis
中东大鹅9 小时前
Mybatis Plus 多数据源
java·数据库·spring boot·后端·mybatis