redis-替代mybatis二级缓存(代码片段)

玩葫芦的卷心菜 玩葫芦的卷心菜     2022-11-18     358

关键词:

文章目录


编程不良人Redis链接
Redis面经属实有点懵,回头补一下

1、二级缓存

作缓存的对象类型需要实现序列化

1.1、cache使用

在dao层对应的mapper配置文件中使用cache标签即可开启二级缓存

<cache/>

缓存是key-value形式,key可以看作select语句(key还包含其他信息’)
开启后,查询语句首先去通过select查询本地缓存,

  • 若发现对应select命中缓存则直接返回结果
  • 若没发现则请求数据库后返回结果会被添加到本地缓存,下次查询发现是同一条语句就会直接返回,不需要请求数据库,大大增加了查询效率

1.2、原理

Mybatis开启Cache后会默认使用实现了Cache接口的PerpetualCache类做缓存操作
也可以通过指定type使用不同的Cache子类做二级缓存

<cache type=""/>
public class PerpetualCache implements Cache 
    private final String id;
    private final Map<Object, Object> cache = new HashMap();

    public PerpetualCache(String id) 
        this.id = id;
    

    public String getId() 
        return this.id;
    

    public int getSize() 
        return this.cache.size();
    

    public void putObject(Object key, Object value) 
        this.cache.put(key, value);
    

    public Object getObject(Object key) 
        return this.cache.get(key);
    

    public Object removeObject(Object key) 
        return this.cache.remove(key);
    

    public void clear() 
        this.cache.clear();
    

    public boolean equals(Object o) 
        if (this.getId() == null) 
            throw new CacheException("Cache instances require an ID.");
         else if (this == o) 
            return true;
         else if (!(o instanceof Cache)) 
            return false;
         else 
            Cache otherCache = (Cache)o;
            return this.getId().equals(otherCache.getId());
        
    

    public int hashCode() 
        if (this.getId() == null) 
            throw new CacheException("Cache instances require an ID.");
         else 
            return this.getId().hashCode();
        
    

单体应用使用二级缓存绰绰有余,但是使用集群后,每个服务对应一个JVM,本地缓存是不共享的,所以就需要使用一个外界中间件提供共享缓存来实现二级缓存-Redis

2、Redis替代二级缓存

上面说到开启cache后使用Cache子类来进行缓存操作
所以我们通过实现Cache的自定义类
使用RedisTemplate来远程操作Redis进行缓存的操作,所有的缓存统一在redis上获取和添加

2.1、获取ApplicationContext

Cache实现类并没有添加到容器中,所以需要获取上下文来注入RedisTemplate

将类添加到容器的方式:@Service、@Controller、@Component等,里面可以随意使用自动注入

@Component
public class ApplicationContextUtils implements ApplicationContextAware 

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
        this.applicationContext=applicationContext;
    

    public static Object getBean(String beanName)
        return applicationContext.getBean(beanName);
    

2.2、自定义cache实现类

1、必须有常量字符串id
2、必须构造器赋予id(为mapper对应namespace,一个dao通常对应一个表的所有操作)

发现使用以id作key的hash类缓存很适合,同一个id下所有key为同一个dao的所有查询语句
hset namespace (select xx from) xxxx
hset namespace (select xx from) xxxx
清空缓存 清空id的对应缓存就将表更新后的对应的所有缓存清掉了
del namespace
缺点是级联查询的缓存有问题,通过cache-ref可解决(在下方)

3、put为添加缓存
4、get为获取缓存
5、当表更新后,就需要清空这张表对应的所有缓存,通过clear实现

public class RedisCache implements Cache 
    private final String id;

    //id指定namespace
    public RedisCache(String id) 
        System.out.println("id==========="+id);
        this.id = id;
    

    @Override
    public String getId() 
        return this.id;
    

    @Override
    public void putObject(Object key, Object value) 
        System.out.println("key==="+key);
        System.out.println("value==="+value);
        getRedisTemplate().opsForHash().put(id,key.toString(),value);
    

    @Override
    public Object getObject(Object key) 
        System.out.println("key:"+key);
        return getRedisTemplate().opsForHash().get(id,key.toString());
    

    @Override
    public Object removeObject(Object o) 
        return null;
    

    @Override
    public void clear() 
        getRedisTemplate().delete(id);
    

    @Override
    public int getSize() 
        return 0;
    
	
	//方便获取redisTemplate
    private RedisTemplate getRedisTemplate()
        RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
        redisTemplate.setKeySerializer(new StringRedisSerializer());//指定key的序列化类型
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());//指定hash类型的key序列化类型
        return redisTemplate;
    

2.3、关联查询的缓存处理

关联查询的时候,会根据两个表进行查询
当其中一个表更新删除对应缓存后,另一张表的关联缓存可能还在就会导致一致性错误

所以通过缓存引用来解决关联查询的缓存问题

在关联查询的任意一方添加缓存引用即可

<cache-ref namespace="com.chime.redis_study.dao.UserDao"/>

当在对应mapper添加缓存引用后,之后该namespace的所有查询都会使用引用的缓存
如在EmpMapper里引用了EmpDao,EmpDao和UserDao共享UserDao的缓存空间,之后任意一表更新就会清空共享的所有缓存

3、缓存优化策略

3.1、对key进行优化

我们发现自动生成的key过长,可以通过MD5加密将其缩减为32位16进制字符串
MD5特点:

  1. 通过MD5加密后生成32位16进制字符串
  2. 不同内容文件经过加密,加密结果不一致(如何比较两文件内容不同?–通过MD5加密后比较加密串)
  3. 相同内容文件多次经过MD5加密结果一致
    @Test
    public void testMd5()
        String key="-453465999:1075164090:com.chime.redis_study.dao.UserDao.findAll:0:2147483647:select id,name,age from user:SqlSessionFactoryBean";
        String s = DigestUtils.md5DigestAsHex(key.getBytes());
        System.out.println(s);
    

a22ac04c2dcd56aa81f82243f644e503

优化的Cache实现类(只需要修改与key关联的put、set就行)

public class RedisCache implements Cache 

    @Override
    public void putObject(Object key, Object value) 
        getRedisTemplate().opsForHash().put(id,getKeyToMd5(key.toString()),value);
    

    @Override
    public Object getObject(Object key) 
        return getRedisTemplate().opsForHash().get(id,getKeyToMd5(key.toString()));
    
    
    public String getKeyToMd5(String key)
        return DigestUtils.md5DigestAsHex(key.getBytes());
    


推荐Redis做缓存时key长度过长使用MD5对key进行优化

redis-替代mybatis二级缓存(代码片段)

文章目录1、二级缓存1.1、cache使用1.2、原理2、Redis替代二级缓存2.1、获取ApplicationContext2.2、自定义cache实现类2.3、关联查询的缓存处理3、缓存优化策略3.1、对key进行优化编程不良人Redis链接Redis面经属实有点懵,回头补一下1... 查看详情

springboot集成redis配置mybatis二级缓存(代码片段)

目录写在前面源码获取一、MyBatis缓存机制1.1、一级缓存1.2、二级缓存二、集成Redis2.1、安装Redis2.2、项目引入Redis2.2.1、Maven依赖2.2.2、配置application.yml2.2.3、配置序列化规则三、配置二级缓存2.1、开启二级缓存2.2、自定义缓存类2.3... 查看详情

mybatis从入门到精通—mybatis缓存和二级缓存整合redis(代码片段)

⼀级缓存缓存验证在⼀个sqlSession中,对user表根据username进⾏两次查询,查看他们发出sql语句的情况@Testpublicvoidtest1()throwsIOExceptionInputStreamresourceAsStream=Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactorysqlSes 查看详情

mybatis(代码片段)

二级缓存为什么有了一级缓存后,还需要有二级缓存呢?二级缓存是应用级缓存,也使得它具有更多的存储方式(redis,内存),而一级缓存只能在内存中存储数据。并且二级缓存存储的是应用整个生... 查看详情

springboot多模块项目applicationcontext无法getbean,mybatisplus二级缓存与放弃mybatis(plus)的二级缓存(代码片段)

SpringBoot多模块项目ApplicationContext无法getBean,MybatisPlus二级缓存与放弃Mybatis(Plus)的二级缓存事情是这样发生的我想用redis实现mybatis-plus的二级缓存,用mybatis的方法(准备好cahce类,在mapper文件里面标记上c... 查看详情

使用redis做mybaties的二级缓存-mybatis二级缓存小心使用

 Mybatis默认对二级缓存是关闭的,一级缓存默认开启;下面就说说为什么使用二级缓存需要注意:    二级缓存是建立在同一个namespace下的,如果对表的操作查询可能有多个namespace,那么得到的数据就是错误的... 查看详情

mybatis一级缓存,mybatis二级缓存,mybatis缓存失效(代码片段)

Mybatis一级缓存,Mybatis二级缓存,Mybatis缓存失效 ================================©Copyright蕃薯耀 2021-06-24https://www.cnblogs.com/fanshuyao/ 一、SpringBoot整合Mybatis1、pom.xml引入依赖(基于SpringBoot:2.3.12.REL 查看详情

03.redis+ssm整合(mybatis二级缓存)

...了,这里不再做代码复制工作。这里主要是利用redis去做mybatis的二级缓存,mybaits映射文件中所有的select都会刷新已有缓存,如果不存在就会新建缓存,所有的insert,update操作都会更新缓存。redis的好处也显而易见,可以使系统的... 查看详情

使用redis做mybatis的二级缓存

使用Redis做MyBatis的二级缓存 通常为了减轻数据库的压力,我们会引入缓存。在Dao查询数据库之前,先去缓存中找是否有要找的数据,如果有则用缓存中的数据即可,就不用查询数据库了。如果没有才去数据库中查找。这样就能... 查看详情

mybatis系列目录--5.mybatis一级缓存和二级缓存(redis实现)

转载请注明出处哈:http://carlosfu.iteye.com/blog/22386620.相关知识:查询缓存:绝大数系统主要是读多写少。缓存作用:减轻数据库压力,提供访问速度。  1.一级缓存测试用例(1)默认开启,不需要有什么配置(2)示意图 (3)测... 查看详情

springboot+mybatis+redis实现二级缓存

对于查询比较多的项目可以考虑配置二级缓存,mybatis本身的二级缓存是缓存到本地,但是对于多个节点的项目来说,可能会出现数据不一致的问题,所以采用redis缓存,这样二级缓存的数据就可以缓存到内存,可实现多个节点项... 查看详情

mybatis缓存专题-一文彻底搞懂mybatis二级缓存(代码片段)

...属性3.1.type3.2.eviction3.3.flushInterval3.4.size3.5readOnly3.6blocking4.MyBatis的缓存机制整体设计以及二级缓存的工作模式5.使用二级缓存,必须要具备的条件6.一级缓存 查看详情

mybatis缓存机制(代码片段)

...介绍2.一级缓存和二级缓存二、一级缓存三、二级缓存3.1mybatis自带的二级缓存3.1.1代码测试二级缓存3.1.2查询结果存入二级缓存的时机3.1.3二级缓存相关配置四、整合EHCache4.1EHCache简介4.2整合操作五、缓存基本原理5.1Cache接口5.2Perpe... 查看详情

mybatis集成redis作为二级缓存

mybatis默认开启了二级缓存功能,在mybatis主配置文件中,将cacheEnabled设置成false,则会关闭二级缓存功能<settings><!--二级缓存默认开启,false关闭--><settingname="cacheEnabled"value="false"/><!--mybatis日志打印到控制台--><set... 查看详情

mybatis二级缓存详解(代码片段)

1 二级缓存简介二级缓存是在多个SqlSession在同一个Mapper文件中共享的缓存,它是Mapper级别的,其作用域是Mapper文件中的namespace,默认是不开启的。看如下图: 整个流程是这样的(不考虑第三方缓存库):当开启二级缓存... 查看详情

mybatis一级缓存与二级缓存的区别你知道吗(代码片段)

前言Java面试经常问到Mybatis一级缓存和二级缓存,今天就给大家重点详解Mybatis一级缓存和二级缓存原理与区别。Mybatis缓存缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存可以避免频繁与数据库... 查看详情

mybatis一级缓存与二级缓存的区别你知道吗(代码片段)

前言Java面试经常问到Mybatis一级缓存和二级缓存,今天就给大家重点详解Mybatis一级缓存和二级缓存原理与区别。Mybatis缓存缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存可以避免频繁与数据库... 查看详情

使用redis作为mybatis的二级缓存

本次介绍一下使用mybatis-redis项目作为mybatis的二级缓存在生产项目中的配置与应用。首先,在pom中添加一下依赖:<!-- mybatis cache --><dependency>    <groupId>org.mybatis.caches</groupId>& 查看详情