mybatis本地缓存&分布式缓存干货分享

前言:干货记录学习mybatis实际开发中缓存的使用。

 	环境: springboot2.X  +  mybatis3.x

Mybatis是一款持久层框架,它提供了一级缓存和二级缓存。

名词解释

  • 一级缓存(mybatis默认开启)
    同一个sqlSession中有效,在同一个SqlSession中,执行两次相同的sql查询,第二次不走数据库查询,而是在缓存中获取。
  • 二级缓存(需要开发者自行添加代码开启)
    二级缓存开启后,不同的sqlSession获取同一数据时,可以不走数据库查询直接从缓存中获取。
    缓存原理:PerpetualCache 的 HashMap本地缓存

二级缓存的开启

 <!--mybatise 配置文件中设置-->
<settings>
	<setting name="cacheEnabled" value="true"/>
</settings>
<!--某一个mapper中开启,mapper 配置文件中设置-->
<cache type="org.apache.ibatis.cache.impl.PerpetualCache" 具体执行缓存操作的类,mybatis默认PerpetualCache,我们可以自定义修改
	   blocking="false" (是否使用阻塞缓存): 默认为false,当指定为true时将采用BlockingCache进行封装,使用BlockingCache会在查询缓存时锁住对应的Key,如果缓存命中了则会释放对应的锁,否则会在查询数据库以后再释放锁这样可以阻止并发情况下多个线程同时查询数据.
	   eviction="LUR" 回收策略 默认 LUR 最近最少使用 
	   flushInterval=""  缓存刷新时间间隔,单位毫秒,不设置则在调用时刷新
	   readOnly="true" 只读 
	   size="1024" 缓存对象的个数 默认1024/> 
<!-- 操作 CUD的 statement时候,会强制刷新二级缓存 -->
<!-- 我们可以指定 某一个 setect 操作 使用缓存或者不使用缓存 useCache 可以指定某一个 cud 操作 是否强制刷新缓存 flushCache -->

**注意:被缓存的对象可以被序列化和反序列化,就是实现实现Serializable接口**

使用redis替换mybatis自身的缓存实现(分布式缓存)

//功能简写了,使用时根据自己实际情况修改
public class MyRedisCache implements Cache {
    private final String id;    //当前放入缓存的Mapper的 namespace 名称空间
    private final Map<Object, Object> cache = new HashMap<>();
    public MyRedisCache(String id) {
        this.id = id;
    }
    // 返回cache的唯一标识
    @Override
    public String getId() {
        return id;
    }
    // 缓存放入值
    // redis --- RedisTemplate  StringRedisTemplate
    @Override
    public void putObject(Object key, Object value) {
        getRedisTemplate().opsForHash().put(key,value);
    }
    // 从缓存中获取值
    @Override
    public Object getObject(Object key) {
        return getRedisTemplate().opsForHash().get(key);
    }
    @Override
    public void clear() {
        //清空namespace
        getRedisTemplate().delete(id.toString());//清空缓存
    }
    ... 
}
<!--使自定义的缓存执行类生效-->
<cache type="...MyRedisCache" .../>

自定义缓存执行类时注意的问题

  • RedisTemplate对象是自动注入到IOC容器中,然后通过ApplicationContext对象回去容器对象。
    在SpringBoot内部提供接口 ApplicationContextAware 获取IOC容器ApplicationContext对象。然后通过applicationContext对象获取Redis操作对象 RedisTemplate 对象。
@Configuration
public class ApplicationContextUtils implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    //工厂中获取对象 工厂中RedisTemplate 默认 name redisTemplate
    public static Object getBean(String beanName){
        return applicationContext.getBean(beanName);
    }
}
  • 通过查看源码得到mybatis做缓存时使用的是Map,那么他的key的设计就很重要了,mybatis是使用mapper的 namespace 和sql做key,我们根据实际情况自己设计,存入redis的key的策略和合适的数据结构存储值(redis的数据结构后续更新)。我使用的是hash结构,redisTemplate.opsForHash().put(namespace,key,value);

最后

感谢您的阅读,各位大佬有什么意见和问题欢迎评论区留言!
觉得文章对你有帮助记得给我点个赞,欢迎大家关注和转发文章!

上一篇:SpringUtils


下一篇:​BeanFactory和ApplicationContext的区别