MyBatis的一级缓存和二级缓存

MyBatis缓存介绍

为什么要用缓存? 

在首次访问时,查询数据库,将查询的数据库信息存入内存中;再次访问时可直接访问缓存,以减少IO、硬盘读写次数、提高效率。

MyBatis的一级缓存和二级缓存

1.一级缓存

一级缓存是mybatis中的SqlSession对象的缓存。当我们执行完查询之后,查询的结果会同时存在在SqlSession为我们提供的一块区域中。当我们再次查询同样的数据,mybatis会先去SqlSession中查询是否有,有的话直接拿出来使用。当SqlSession对象消失时,Mybatis的一级缓存也就消失了。

2.二级缓存

二级缓存是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessioFactory对象创建的SqlSession共享其缓存。

我们可以通过案例来解释一级缓存和二级缓存。

MyBatis一级缓存案例

首先我们需要创建好类和Mapper以方便接下来的测试

Pojo

package com.by.pojo;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private  String 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 + '\'' +
                '}';
    }
}

Mapper

package com.by.mapper;

import com.by.pojo.User;

import java.util.List;

public interface UserMapper {
    public User findById(int id);

    void deleteById(Integer id);
}

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.by.mapper.UserMapper">
<cache></cache>
    <select id="findById" resultType="com.by.pojo.User">
        select * from user where id =#{id};
    </select>

<delete id="deleteById" parameterType="int">
    delete from user where id=#{id}
</delete>
</mapper>

Test

test1

    @Test
    public void testCache(){
        System.out.println("=========第一次输出========");
        UserMapper userMapper = session.getMapper(UserMapper.class);
        User user = userMapper.findById(42);
        System.out.println(user);
        System.out.println("=========第二次输出========");
        User user2=userMapper.findById(42);
        System.out.println(user2);
    }

运行结果:

用同一个SqlSession创建的mapper第二次调用会直接读取缓存中的结果。

test2

    @Test
    public void testCache2(){
        SqlSession session1 = sessionFactory.openSession();
        SqlSession session2=  sessionFactory.openSession();
        UserMapper userMapper1 = session1.getMapper(UserMapper.class);
        UserMapper userMapper2 = session2.getMapper(UserMapper.class);
        System.out.println("=============第一次输出=============");
        User user1 = userMapper1.findById(43);
        System.out.println(user1);
        System.out.println("=============修改一次===============");
        userMapper1.deleteById(89);
        System.out.println("=============第二次输出==============");
        User user2 = userMapper2.findById(43);
        System.out.println(user2);
    }

运行结果:

当使用不同的SqlSeesion或者在中间进行修改、添加、删除操作时会重新加载缓存。

一级缓存案例分析

  1. 第一次发起查询用户id为 1 的用户信息,先去找缓存中是否有id为 1 的用户信息,如果没有,从数据库查询用户信息。 得到用户信息,将用户信息存储到一级缓存中。

  2. 如果sqlSession去执行 commit操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读

  3. 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

MyBatis二级缓存案例

Mapper.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.by.mapper.UserMapper">
<cache></cache>
    <select id="findById" resultType="com.by.pojo.User">
        select * from user where id =#{id};
    </select>

<delete id="deleteById" parameterType="int">
    delete from user where id=#{id}
</delete>
</mapper>

Test

test1

 @Test
    public void testCache(){
        SqlSession session1 = sessionFactory.openSession();
        SqlSession session2 = sessionFactory.openSession();
        UserMapper userMapper1 = session1.getMapper(UserMapper.class);
        UserMapper userMapper2 = session2.getMapper(UserMapper.class);
        System.out.println("===============第一次查询================");
        User user1 = userMapper1.findById(41);
        System.out.println(user1);
        session1.close();
        System.out.println("===============第二次查询================");
        User user2 = userMapper2.findById(41);
        System.out.println(user2);
    }

运行结果:

当利用一个sqlSessionFactory创建多个sqlSession并操作同一个查询语句时, 多个sqlSession可共用二级缓存。

test2

  @Test
    public void testNoCache2() throws IOException {
        InputStream is1 = Resources.getResourceAsStream("mybatis-config.xml");
        InputStream is2 = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sessionFactory1 = new SqlSessionFactoryBuilder().build(is1);
        SqlSessionFactory sessionFactory2 = new SqlSessionFactoryBuilder().build(is2);
        SqlSession session1 = sessionFactory1.openSession();
        SqlSession session2 = sessionFactory2.openSession();
        UserMapper userMapper1 = session1.getMapper(UserMapper.class);
        UserMapper userMapper2 = session2.getMapper(UserMapper.class);
        System.out.println("============第一次查询===============");
        User user1 = userMapper1.findById(43);
        System.out.println(user1);
        session1.close();
        System.out.println("=============删除====================");
        userMapper2.deleteById(79);
        System.out.println("==============第二次查询===============");
        User user2 = userMapper2.findById(43);
        System.out.println(user2);
    }

运行结果:

和一级缓存差不多的是:当创建不同的sqlSessionFactory创建session或者查询过程中对其进行修改、添加、删除时都会重新读取。

二级缓存案例分析:

二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

一级缓存和二级缓存的区别

一级缓存:

范围:sqlSession

配置:默认开启

走缓存:同一个sqlSession

不走缓存:不同的sqlSession或者两次查询中间执行了增删改

二级缓存:

范围:sqlSessionFactory

配置:<cache></cache>

走缓存:同一个sqlSessionFactory

不走缓存:不同的sqlSessionFactory或者两次查询中间执行了增删改

  • 45
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值