资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

怎么在Springboot2.0通过redis实现支持分布式的mybatis二级缓存

这篇文章主要介绍“怎么在Springboot2.0通过redis实现支持分布式的mybatis二级缓存”,在日常操作中,相信很多人在怎么在Springboot2.0通过redis实现支持分布式的mybatis二级缓存问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么在Springboot2.0通过redis实现支持分布式的mybatis二级缓存”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

我们提供的服务有:成都网站建设、成都网站设计、微信公众号开发、网站优化、网站认证、安泽ssl等。为千余家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的安泽网站制作公司

最近领导要求在项目中加下mybatis二级缓存,由于当前项目是分布式微服务,且是多节点部署的,而司内缓存中间件使用的redis,那很自然的要用redis做分布式缓存支持,避免出现直接使用原生mybatis二级缓存造成缓存数据不一致等问题。下面会对基于redis的mybatis二级缓存实现做下简单介绍,涉及一些概念,同时一些坑点做下整理。

1. 一级缓存

一级缓存是在SqlSession级别的缓存,MyBatis默认开启一级缓存。即同一个SqlSession对象,相同参数多次调用同一个Mapper方法时,只执行一次SQL,第一次查询后数据被缓存起来,之后的调用在没有缓存刷新、超时情况下都是直接先从缓存中取数据,不再去查数据库。不同SqlSession间,缓存是隔离的。

怎么在Springboot2.0通过redis实现支持分布式的mybatis二级缓存

此外实际项目开发中,一级缓存存在很大的局限性,我们的项目一般是Spring+Mybatis集成开发,而Spring的事务管理在逻辑层,每个service对应不同的SqlSession(这是通过MapperScannerConfigurer类创建SqlSession自动注入到service中的), 每次查询之后都会关闭SqlSession,缓存数据就会被清空。所以Spring整合之后,如果没有事务,一级缓存是没有实际意义的。

2. 二级缓存

二级缓存是Mapper级别的缓存,Mybatis默认不开启二级缓存。二级缓存的作用域是mapper的namespace,即相同namespace的两个mapper将共用同一缓存区域;支持跨SqlSession,即多个SqlSession可以共享一个mapper缓存。实现上是基于PerpetualCache的HashMap做本地存储,也支持自定义三方存储如ehcache、redis、memcache等,用于支持分布式。在本地使用HashMap存储缓存时,key为hashCode+sqlId+Sql语句(查询参数好像也参与,demo用的selectAll,没怎么关注),其他三方存储时key也差不多。

怎么在Springboot2.0通过redis实现支持分布式的mybatis二级缓存

注意:开启二级缓存后

  • 所有在映射文件里的select 语句都将被缓存。

  • 所有在映射文件里insert,update 和delete 语句会清空缓存。

  • 缓存默认使用“最近很少使用”LRU算法来回收

  • 缓存不会被设定的时间所清空。

  • 每个缓存可以存储1024 个列表或对象的引用(不管查询出来的结果是什么)。

  • 缓存将作为“读/写”缓存,意味着获取的对象不是共享的且对调用者是安全的。不会有其它的调用干扰其他调用者或线程所做的潜在修改

实现步骤:

1、全局cache-enable开关设置,此开关默认为true(实践证明不设置也行)

  • 创建mybatis-config.xml的配置文件

  • Mybatis配置SqlSessionFactory时加载该配置

factory.setConfigLocation(new ClassPathResource("mybatis-config.xml"));

注:通过mybatis-config.xml配置缓存开关,验证启停正常;通过配置属性mybatis.configuration.cache-enabled=true的设置不起作用,原因有待探究

2、mapper.xml中缓存标签的开启

  • 这是二级缓存开启的关键,如下配置是mybatis本地缓存,作用于整个mapper的所有查询,若某个       SELECT * FROM table WHERE user_id = #{userId}   

    3、Model实体类需要做序列化

    public class User implements Serializable{
       private static final long serialVersionUID = -6596381461353742505L;
       ...
    
    }

    本文是以redis作为存储介质,在redis配置时即指定了key、value的序列化方式,所以我在这步时实体类上序列化可有可无(也有人说即使本地缓存也不需要)

    执行示例结果:

    怎么在Springboot2.0通过redis实现支持分布式的mybatis二级缓存

    坑点整理:

    在第二步实现时,我用了标签来开启二级缓存,此处还可以在mybatis的mapper接口类上使用等效注解来开启二级缓存,注解如下:

    @CacheNamespace(implementation = com.xxx.xxx.configs.MybatisRedisCache.class)

    但使用注解和xml中标签不能同时作用,也就是说使用注解时,只能在Mapper接口的方法上用@Select注解绑定执行SQL,缓存才有效;同样使用标签,则只能在mapper.xml中定义