缓存

缓存的介绍

MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。多查询的情况下使用缓存,因为我们网站情况多是通过查询数据库来展示资源,查询数据库是消耗资源的、性能低的,所以我们只在第一次查询的时候连接数据库查询,查询之后会进行一个缓存,当下次在进行查询的时候就可以直接在缓存中查取了。

映射语句文件中的所有 select 语句的结果将会被缓存。
映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
缓存不会定时进行刷新(也就是说,没有刷新间隔)。
缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

一级缓存

以及缓存其实就是Sqlsession对象,他是默认情况下就开启的。
测试类,进行查询操作。

 @Test
    public void test4(){
        //创建一次SqlSession
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //查询id为1的
        User userId = mapper.getUserId(1);
        System.out.println(userId);
        //再次查询id为1的
        User userId1 = mapper.getUserId(1);
        System.out.println(userId1);
        //进行判断 true
        System.out.println(userId==userId1);
        sqlSession.close();
    }

添加了一条插入操作,缓存会进行清空 操作。

@Test
    public void test4(){
        //创建一次SqlSession
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //查询id为1的
        User userId = mapper.getUserId(1);
        System.out.println(userId);
        
        //进行插入操作
        int add = mapper.getAdd(new User(5, "aa", "aa"));
        if (add>0){
            System.out.println("执行成功");
        }
        
        //再次查询id为1的
        User userId1 = mapper.getUserId(1);
        System.out.println(userId1);
        //进行判断 false
        System.out.println(userId==userId1);
        sqlSession.close();
    }

手动清除缓存;

@Test
    public void test4(){
        //创建一次SqlSession
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //查询id为1的
        User userId = mapper.getUserId(1);
        System.out.println(userId);
        
       //手动清除缓存
        sqlSession.clearCache();
        
        //再次查询id为1的
        User userId1 = mapper.getUserId(1);
        System.out.println(userId1);
        //进行判断 false
        System.out.println(userId==userId1);
        sqlSession.close();
    }

缓存失效的几种情况
1.查询不同的东西。
2.增删该操作可能会改变原来的东西,所以缓存必定刷新。
3.查询不同Mapper.xml。
4.手动清除缓存。

二级缓存

默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

<cache/>

下面这些都是对这些属性的解释。

这些属性可以通过 cache 元素的属性来修改。比如:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表面的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

可用的清除策略有:

LRU – 最近最少使用:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
默认的清除策略是 LRU。

flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。

size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。

readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。

工作机制
一条数据查询会存到一级缓存中,当会话关闭的时候,会存到二级缓存中,在创建新的会话会在二级缓存中获取,不同mapper会存在不同缓存中。

首先是我们需要在setting里面开启缓存设置

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

mapper添加<cache标签

<mapper namespace="aw.dao.UserMapper">
    <cache
            eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"/>

    <select id="getUserId"  resultType="aw.pojo.User" parameterType="int">
        select * from user where id=#{id}
    </select>
</mapper>

测试类

   @Test
    public void test5(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userId = mapper.getUserId(1);
        System.out.println(userId);
//        手动清除缓存
//        sqlSession.clearCache();
//        sqlSession结束会话 也是清除缓存
        sqlSession.close();


        SqlSession sqlSession1 = MybatisUtils.getSqlSession();
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        User userId1 = mapper1.getUserId(1);
        System.out.println(userId1);
        sqlSession1.close();
        //返回的结果都是true
        System.out.println(userId==userId1);


    }

自定义缓存

我们可以根据自己的情况定义缓存情况。
首先是进行导入包,尽量选mybatis兼容性高。

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>

在mapper.xml中添加路径,EhcacheCache这是我们引用第三方的,也可以自己写。

 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

添加配置文件,ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--
       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
       user.home – 用户主目录
       user.dir  – 用户当前工作目录
       java.io.tmpdir – 默认临时文件路径
     -->
    <diskStore path="java.io.tmpdir/Tmp_EhCache"/>
    <!--
       defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
     -->
    <!--
      name:缓存名称。
      maxElementsInMemory:缓存最大数目
      maxElementsOnDisk:硬盘最大缓存个数。
      eternal:对象是否永久有效,一但设置了,timeout将不起作用。
      overflowToDisk:是否保存到磁盘,当系统当机时
      timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
      timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
      diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
      diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
      diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
      memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
      clearOnFlush:内存数量最大时是否清除。
      memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
      FIFO,first in first out,这个是大家最熟的,先进先出。
      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
      LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
   -->
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>

</ehcache>

我们也可以自己写一个类继承他的接口。

你可以使用所有简单类型作为 JavaBean 属性的类型,MyBatis 会进行转换。
 你也可以使用占位符(如 ${cache.file}),以便替换成在配置文件属性中定义的值。

从版本 3.4.2 开始,MyBatis 已经支持在所有属性设置完毕之后,调用一个初始化方法。
 如果想要使用这个特性,请在你的自定义缓存类里实现 org.apache.ibatis.builder.InitializingObject 接口。

public interface InitializingObject {
  void initialize() throws Exception;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值