zoukankan      html  css  js  c++  java
  • MyBaits缓存

    一级缓存(作用域SqlSession)

    • MyBatis的一级查询缓存(也叫作本地缓存)是基于org.apache.ibatis.cache.impl.PerpetualCache 类的 HashMap本地缓存,其作用域是SqlSession
    • 在同一个SqlSession中两次执行相同的 sql 查询语句,第一次执行完毕后,会将查询结果写入到缓存中,第二次会从缓存中直接获取数据,而不再到数据库中进行查询,这样就减少了数据库的访问,从而提高查询效率。
    • 当一个 SqlSession 结束后,该 SqlSession 中的一级查询缓存也就不存在了。
    • myBatis 默认一级查询缓存是开启状态,且不能关闭。
    • 增删改会清空缓存,无论是否commit
    • spring整合mybatis后,非事务环境下,每次操作数据库都使用新的sqlSession对象。因此mybatis的一级缓存无法使用(一级缓存针对同一个sqlsession有效)
    • 在开启事物的情况之下,spring使用threadLocal获取当前资源绑定同一个sqlSession,因此此时一级缓存是有效的

    二级缓存(作用域namespace)

    • MyBatis的二级缓存是mapper范围级别的
    • SqlSession关闭后才会将数据写到二级缓存区域
    • 增删改操作,无论是否进行提交commit(),均会清空一级、二级缓存
    • 二级缓存会使用 Least Recently Used (LRU,最近最少使用的)算法来收回。
    • 根据时间表(如 no Flush Interval ,没有刷新间隔),缓存不会以任何时间顺序来刷新 。
    • 缓存会存储集合或对象(无论查询方法返回什么类型的值)的 1024 个引用。
    • 缓存会被视为 read/write (可读/可写)的,意味着对象检索不是共享的,而且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改 。
    • 设置方式在mapper文件中添加<cache/>

    二级缓存该用么?

    多表操作一定不要使用二级缓存,因为多表操作进行更新操作,一定会产生脏数据。而且二级缓存是表级缓存,开销大,没有一级缓存直接使用 HashMap 来存储的效率更高,所以二级缓存并不推荐使用。

    二级缓存之Ehcache(本机)

      EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。

      优点:

    1. 快速

    2. 简单

    3. 缓存数据有两级:内存和磁盘,因此无需担心容量问题

    4. 缓存数据会在虚拟机重启的过程中写入磁盘

    5. 可以通过RMI、可插入API等方式进行分布式缓存

    6. 具有缓存和缓存管理器的侦听接口

    7. 支持多缓存管理器实例,以及一个实例的多个缓存区域

    8. 提供Hibernate的缓存实现

    9. 多种缓存策略,Ehcache提供了对大数据的内存和硬盘的存储,最近版本允许多实例、保存对象高灵活性、提供LRU、LFU、FIFO淘汰算法,基础属性支持热配置、支持的插件多

    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>2.10.6</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis.caches</groupId>
        <artifactId>mybatis-ehcache</artifactId>
         <version>1.1.0</version>
    </dependency>
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

      缺点

    1. 使用磁盘Cache的时候非常占用磁盘空间:这是因为DiskCache的算法简单,该算法简单也导致Cache的效率非常高。它只是对元素直接追加存储。因此搜索元素的时候非常的快。如果使用DiskCache的,在很频繁的应用中,很快磁盘会满。

    2. 不能保证数据的安全:当突然kill掉java的时候,可能会产生冲突,EhCache的解决方法是如果文件冲突了,则重建cache。这对于Cache数据需要保存的时候可能不利。当然,Cache只是简单的加速,而不能保证数据的安全。如果想保证数据的存储安全,可以使用Bekeley DB Java Edition版本。这是个嵌入式数据库。可以确保存储安全和空间的利用率。

    二级缓存之Redis(分布式适用)

    pom依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency> 
    <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.7.0</version>
    </dependency>

    redishelper

    package com.zqh.cache;
    
    import com.zqh.config.ApplicationContextHolder;
    import org.apache.ibatis.cache.Cache;
    import org.springframework.data.redis.core.RedisTemplate;
    
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * 1.使用@Component的方式,是spring的方式,会生成一个RedisCache的实例,纳入spring容器中,
     *    在这个容器中实例,是可以注入RedisTemplate。
     * 2.因为在每个mapper中,配置了二级缓存,对应的mapper会重新生成实例,生成的这个实例没有按照spring的规则来生成。
     *   所以这个类中加入了 @Resource @AutoWire都是无法获取。
     * 3.那么如何获取spring容器中的对象了?就需要先拿到spring容器,然后从容器中去手动取。
     */
    
    public class RedisCache implements Cache {  //要想使用Mybatis的二级缓存,必须要实现Cache接口
    
        private RedisTemplate<Object, Object> redisTemplate;
    
        private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    
        private String id;
    
        // id的作用是将不同的mapper作一个区分
        public RedisCache(String id) {
            this.id = id;
        }
    
        // 获取RedisTemplate
        private RedisTemplate<Object, Object> getRedisTemplate() {
            this.redisTemplate = ApplicationContextHolder.getRedisTemplate();
            return redisTemplate;
        }
    
        @Override
        public void putObject(Object key, Object value) {
            getRedisTemplate().opsForValue().set(key, value);
        }
    
        @Override
        public Object getObject(Object key) {
            return getRedisTemplate().opsForValue().get(key);
        }
    
        @Override
        public Object removeObject(Object key) {
            return getRedisTemplate().delete(key);
        }
    
        @Override
        public int getSize() {
            return 1;
        }
    
        @Override
        public String getId() {
            return this.id;
        }
    
        // 不用实现
        @Override
        public void clear() {
        }
    
        @Override
        public ReadWriteLock getReadWriteLock() {
            return this.reentrantReadWriteLock;
        }
    }
    View Code

    获取ApplicationContext

    package com.zqh.config;
    
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Component;
    
    /**
     * spring提供了很多的接口 XXXXAware, 这一类的接口比较的特殊, 那么spring容器在启动的时候
     * 如果检测某个类实现了这一类接口,那么会去调用实现了该接口方法的实现。
     */
    @Component
    public class ApplicationContextHolder implements ApplicationContextAware {
    
        private static ApplicationContext applicationContext;
    
        // 该放方法会自动将spring容器的类 ApplicationContext, 传入给该方法。
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            ApplicationContextHolder.applicationContext = applicationContext;
        }
    
        // 从容器中获取RedisTemplate
        public static RedisTemplate getRedisTemplate() {
            return applicationContext.getBean("redisTemplate", RedisTemplate.class);
        }
    }
    View Code

    mapper配置

        <!--
           在这里配置缓存,那么每个Mapper都会去生成 RedisCache的实现类
         -->
         <!--
            flushInterval: 清空缓存的时间间隔,单位为毫秒; 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用更新语句时刷新。
            size: 可以被设置为任意正整数, 缓存的数量,默认是1024;
            evication: LRU 移除最长时间不被使用的对象。
            blocking: 默认是false;
         -->
        <cache size="1024" type="com.qf.cache.RedisCache"></cache>
    View Code

    Mybatis的二级缓存作用相对有限,特别是在分布式场景及复杂业务场景。建议不开启,直接用在逻辑层自己控制redis。

  • 相关阅读:
    缺少环境变量导致Xilinx Platform Studio无法打开之解决方法
    PS利用EMIO控制LED灯
    利用zedboard添加自定义IP核完成简易计算器
    读后感 关于 《不要一辈子靠技术混饭吃》(挪窝第一篇)
    挪窝了,再谈blog
    windows server 2008 无法打开角色,角色错误,刷新服务器时出现意外错误,HRESULT:0x80070422
    Linux 基础正则表达式和扩展正则表达式
    Linux 基础正则表达式
    Linux 通配符与特殊符号
    Linux 基础命令
  • 原文地址:https://www.cnblogs.com/wishonline/p/13395830.html
Copyright © 2011-2022 走看看