Mybatis框架之延时加载与查询缓存

在上一篇博客 Mybatis框架之快速入门(别再翻了,此篇博客就够了) 介绍了Mybatis框架基本使用细节,在本篇博客将介绍一下延时加载与查询缓存相关内容。

一、延时加载

延时加载,当用到的时候再去访问数据库加载数据,也称为懒加载
此加载策略默认是不开启的,需要手动开启。

1、懒加载开启方法:

在Mybatis主配置文件中添加lazyLoadingEnabled即可。
在这里插入图片描述

测试示例:

懒加载示例实体类之间的关系,一个OrderItem对象包含一个Product对象,一个Order对象包含多个OrderItem对象。关于示例的更新细节,请参考我的另外一篇博客 Mybatis框架之实体之间的关系处理(关联查询)(附Demo:用户和订单)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试源码:

package cn.hestyle.test;

import cn.hestyle.entity.Order;
import cn.hestyle.entity.OrderItem;
import cn.hestyle.mapper.OrderMapper;
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;
import java.util.List;

/**
 * description: 懒加载测试
 *
 * @author hestyle
 * @version 1.0
 * @className mybatis_day_01->LazyLoadingTest
 * @date 2020-01-26 19:20
 **/
public class LazyLoadingTest {
    private static InputStream inputStream;
    private static SqlSessionFactory sqlSessionFactory;
    private static SqlSession sqlSession;
    private static OrderMapper orderMapper;

    static {
        try {
            //读取Mybatis配置文件
            inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            //创建sqlSessionFactory,然后获取sqlSession
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = sqlSessionFactory.openSession();
            orderMapper = sqlSession.getMapper(OrderMapper.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testLazyLoading() throws IOException {
        //查找所有的order
        List<Order> orderList = orderMapper.findAll();
        for (Order order : orderList) {
            System.err.println("=========================分割线===========================");
            System.err.println(order);
            for (OrderItem orderItem : order.getOrderItemList()) {
                System.err.println(orderItem);
            }
        }
        sqlSession.close();
    }
}

2、立即加载(默认)

在这里插入图片描述

3、懒加载(手动配置)

两张图就是SQL执行与打印结果顺序不同,懒加载是用到的时候再去访问数据库。
在这里插入图片描述

4、注意

在mybatis中,resultMap标签 的association标签和collection标签才具有延迟加载的功能。
在这里插入图片描述

二、查询缓存

所谓Mybatis查询缓存,就是当我们从数据库查找出数据时,Mybatis会将查询结果在内存中做一个暂存。当我们再次查找数据时,它会自动去查找缓存内有没有需要查找的结果,如果在缓存中查找到了,则直接从缓存中取,否则再去访问数据库查找需要的数据。看下面的示例就懂了什么是查询缓存。
在这里插入图片描述
Mybatis查询缓存根据作用的范围又可以分成一级缓存二级缓存

1、一级缓存

此缓存 \color{red}默认开启 ,缓存范围是同一个SqlSession,即同一个SqlSession查找到的结果可共享。
在这里插入图片描述
同一个SqlSession每次进行查找数据时,默认暂存到一个共同的位置,当此SqlSession进行数据插入更新删除事务提交SqlSession关闭时,缓存内容清空。
在这里插入图片描述

2、二级缓存

此缓存 \color{red}默认不开启,需要手动配置 ,缓存的范围是整个SqlSessionFactory,同一个SqlSessionFactory生成的所有SqlSession都共享。
一级缓存与二级缓存之间的关系。
在这里插入图片描述

①、二级缓存开启方式

在Mybatis主配置文件中配置
在这里插入图片描述
在需要开启二级缓存的mapper命名空间中配置
在这里插入图片描述
在需要开启二级缓存的实体类实现序列化接口
在这里插入图片描述

扫描二维码关注公众号,回复: 9414807 查看本文章
②、二级缓存效果
package cn.hestyle.test;

import cn.hestyle.entity.User;
import cn.hestyle.mapper.UserMapper;
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;

/**
 * description: 缓存测试
 *
 * @author hestyle
 * @version 1.0
 * @className mybatis_day_01->CashTest
 * @date 2020-01-26 19:42
 **/
public class CashTest {
    private static InputStream inputStream;
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //读取Mybatis配置文件
            inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            //创建sqlSessionFactory,然后获取sqlSession
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testCash(){
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);

        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

        User user1 = userMapper1.findUserById(1);
        System.err.println(user1);
        System.err.println("=================分割线=================");
        //两个SqlSession来自于同一个sqlSessionFactory,按道理存在二级缓存,不用再次访问数据库
        User user2 = userMapper2.findUserById(1);
        System.err.println(user2);
        sqlSession1.close();
        sqlSession2.close();
    }
}

控制天输出结果:
在这里插入图片描述

\color{red}原因: 默认缓存只有一级缓存,只有开启了二级缓存、并且响应的SqlSession进行了事务提交、关闭,该SqlSession产生的一级缓存内容才会转化为同一个SqlSessionFactory的二级缓存。

package cn.hestyle.test;

import cn.hestyle.entity.User;
import cn.hestyle.mapper.UserMapper;
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;

/**
 * description: 缓存测试
 *
 * @author hestyle
 * @version 1.0
 * @className mybatis_day_01->CashTest
 * @date 2020-01-26 19:42
 **/
public class CashTest {
    private static InputStream inputStream;
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //读取Mybatis配置文件
            inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            //创建sqlSessionFactory,然后获取sqlSession
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testCash(){
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);

        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

        User user1 = userMapper1.findUserById(1);
        System.err.println(user1);
        sqlSession1.commit();
        System.err.println("=================分割线=================");
        //两个SqlSession来自于同一个sqlSessionFactory,
        //并且SqlSession1进行了提交、UserMapper开启了二级缓存,不用再次访问数据库
        User user2 = userMapper2.findUserById(1);
        System.err.println(user2);
        sqlSession1.close();
        sqlSession2.close();
    }
}

控制台输出结果:
在这里插入图片描述
与一级缓存一样,如果SqlSessionFactory中的某个SqlSession进行了数据插入、删除、修改,整个二级缓存同样会进行清空。

package cn.hestyle.test;

import cn.hestyle.entity.User;
import cn.hestyle.mapper.UserMapper;
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;

/**
 * description: 缓存测试
 *
 * @author hestyle
 * @version 1.0
 * @className mybatis_day_01->CashTest
 * @date 2020-01-26 19:42
 **/
public class CashTest {
    private static InputStream inputStream;
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //读取Mybatis配置文件
            inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            //创建sqlSessionFactory,然后获取sqlSession
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testCash(){
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);

        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

        User user1 = userMapper1.findUserById(1);
        System.err.println(user1);
        sqlSession1.commit();
        System.err.println("=================分割线=================");
        //两个SqlSession来自于同一个sqlSessionFactory,
        //并且SqlSession1进行了提交、UserMapper开启了二级缓存,不用再次访问数据库
        user1.setUsername("hestyle-修改-修改");
        userMapper1.update(user1);
        sqlSession1.commit();
        //但是由于sqlSession1进行了数据更新,整个SqlSessionFactory的二级缓存全部被清空
        User user2 = userMapper2.findUserById(1);
        System.err.println(user2);
        sqlSession1.close();
        sqlSession2.close();
    }
}

在这里插入图片描述
以上就是Mybatis框架中的延时加载与查询缓存的主要内容,顺带一提,查询缓存主要用于对数据响应速度高,并且数据不怎么修改的场景,否则频繁创建、清空缓存,效率会大大降低。

发布了976 篇原创文章 · 获赞 230 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/104086489