mybatis的一级缓存和二级缓存

一级缓存

1、说明

mybatis默认开启一级缓存,一级缓存的作用域是SqlSession范围的,当在同一个sqlSession中执行两次相同的sql语句时,第一次执行完毕会将数据库中查询的数据写到缓存,第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。

在分布式的环境中,mybatis的一二级缓存非常危险,二级缓存一定要关闭,一级缓存视情况关闭

mybatis的一级缓存和二级缓存_第1张图片

一级缓存失效的四种情况:

  1. sqlSession不同。
  2. sqlSession相同,查询条件不同。因为缓存条件不同,缓存中还没有数据。
  3. sqlSession相同,在两次相同查询条件中间执行过增删改操作。(因为中间的增删改可能对缓存中数据进行修改,所以不能用)
  4. sqlSession相同,手动清空了一级缓存。

2、关闭方法

(1)注解形式

使用注解 @Options(flushCache = Options.FlushCachePolicy.TRUE) 可指定仅仅某个Mapper关闭注解)

@Options(flushCache = Options.FlushCachePolicy.TRUE)
@Select("select * from ge_jdbc_datasource where id = #{id,jdbcType=BIGINT} and status = 1")
@ResultMap("resultMap")
JdbcDataSource find(Long id);

(2)传入随机数

比如sql传参random()数值 或者 sql传入当前时间毫秒数,切记一定要从方法形参传过去而不要在sql中拼写,否则无效

举例说明:下面方式无效

select id from ge_jdbc_datasource where id = 1 and STATUS = 1 AND NOW()=NOW()

(3)设置 statementType

mapperselect 标签中设置 statementType=STATEMENT

statementType的设置有3种:

  1. STATEMENT:直接操作sql,不进行预编译,获取数据
  2. PREPARED:(默认)预处理,参数,进行预编译,获取数据
  3. CALLABLE:执行存储过程————CallableStatement

(4)设置 flushCache

mapperselect 标签中设置 flushCache=“true”

(5)设置 localCacheScope

全局设置 localCacheScope=STATEMENT

参考:https://blog.csdn.net/u011649691/article/details/116058056

2、案例

我们在 getPaymentById 方法中写了两次查询,并且保证方法内的 sqlSession 是同一个。在两次查询期间对数据进行修改,将 serial=001 修改为 serial=002

package com.scy.springcloud.service.impl;

import com.scy.springcloud.dao.PaymentDao;
import com.scy.springcloud.entities.Payment;
import com.scy.springcloud.service.PaymentService;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

@Service
public class PaymentServiceImpl implements PaymentService {
    @Resource
    private PaymentDao paymentDao;

    //这里注入的sqlSession是org.mybatis.spring.SqlSessionTemplate
    /*@Resource
    public SqlSession sqlSession;*/

    @Resource
    SqlSessionFactory sqlSessionFactory;

    @Override
    public Payment getPaymentById2(Long id) {
        //org.apache.ibatis.session.defaults.DefaultSqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Payment payment = sqlSession.selectOne("getPaymentById", id);
        System.out.println(payment.toString());
        try {
            Thread.sleep(10*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Payment payment2 = sqlSession.selectOne("getPaymentById", id);
        System.out.println(payment2.toString());
        sqlSession.close();
        return payment2;
    }
}

查询1(开启缓存)

两次查询是同样的,没有改变,说明开启了一级缓存。

Payment(id=31, serial=001)
Payment(id=31, serial=001)

查询2(关闭缓存)

select 标签中加入 flushCache="true" 后,使一级缓存失效。

<select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap" flushCache="true">
    select * from payment where id = #{id};
select>

第二次查询结果变为serial=002,说明一级缓存失效。

Payment(id=31, serial=001)
Payment(id=31, serial=002)

二级缓存

1、说明

MyBatis的二级缓存是Application级别的缓存,二级缓存的作用域默认为mapper(namespace)

工作机制:

  1. 一个会话,查询一条数据,这个数据会被放在当前会话的一级缓存中。

  2. 如果会话被关闭了,一级缓存中的数据会被保存到二级缓存。新的会话查询信息就会参照二级缓存。

  3. sqlSession > Employee>employee

    sqlSession >DepartmentMapper=>Department

    不同的namespace查出的数据会放在自己对应的缓存中。

效果:

查出的数据首先放在一级缓存中,只有一级缓存被关闭或者提交以后,一级缓存数据才会转移到二级缓存

2、开启方法

(1)方式一

mybatis 的配置文件中进行配置

<configuration>
	<settings>
		
		<setting name="cacheEnabled" value="true"/>
	settings>
configuration>

(2)方式二

application.yml文件中进行配置开启mybatis的二级缓存 mybatis.configuration.cache-enabled=true

# 开启二级缓存
mybatis:
  configuration:
    cache-enabled: true

# 开启sql打印(可以方便查看是否使用了缓存)
logging:
  level:
    com.scy.springcloud.dao: debug

3、开启缓存配置

开启二级缓存的分开关。

要加入cache的配置二级缓存才会开启。

<mapper namespace="com.scy.springcloud.dao.PaymentDao">
    
    <cache eviction="LRU" flushInterval="20000" readOnly="true" size="1024">
    cache>
mapper>

cache 相关属性:

  • eviction: 缓存的回收策略

    • LRU(默认):最近最少使用,移除最长时间不被使用的对象
    • FIFO:先进先出,安对象进入缓存的顺序来移除它们
    • SOFT:软引用,移除基于垃圾回收器的状态和软引用规则的对象
    • WEAK: 弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象
  • flushInterval:缓存刷新间隔 缓存多长时间清空一次,默认不清空,设置一个毫秒值

  • readOnly:是否只读 。

    • true:只读,mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。 mybatis为了加快获取速度,直接会将数据在缓存中的引用交给用户,不安全,但速度快。
    • false:非只读,mybatis觉得获取的数据可能会被修改。会利用序列化&反序列化的技术克隆一份新的数据给你,安全,但速度慢。
  • size:缓存最多存放多少个引用。默认1024。

  • type:指定自定义缓存的全类名,实现Mybatis提供的Cache接口即可。

注意事项:

实体对象要 implements Serializable ,否则报错

public class User implements Serializable{
}

启动工程,如果出现

Cache Hit Ratio . # 表示缓存开启了.....

参考:

Mybatis二级缓存失效及二级缓存使用简介
https://blog.csdn.net/sao_jie/article/details/119297811

浅谈一下mybatis中@CacheNamespace和@CacheNamespaceRef的区别以及使用

https://blog.csdn.net/lovely960823/article/details/111277801

你可能感兴趣的:(Java,mybatis缓存,一级缓存,二级缓存)