日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

使用Redis做Mybatis的二級緩存

作者:鑄鍵為犁 更新時間: 2023-07-25 編程語言

文章目錄

  • 前言
  • 一、二級緩存
  • 二、使用步驟
    • 1.開啟二級緩存
    • 2.編寫ApplicationContextHolder
    • 3.編寫RedisCache二級緩存工具類
    • 4.在mapper.xml文件中開啟全局二級緩存
    • 5.配置RedisTemplate序列化工具類,實體也需要實現序列化接口
  • 三、測試
  • 總結


前言

本篇記錄怎么使用Redis做Mybtais的緩存。


一、二級緩存

MyBatis中的緩存分為一級緩存和二級緩存

  • 一級緩存:基于sqlSession的緩存
  • 二級緩存:基于多個sqlSession 共享的namspace數據塊

通常一個mapper 都一個namespace,所有的相關二級緩存都存在該namespace 數據塊下
查詢順序:先去二級緩存,如果二級沒有再去一級緩存,一級沒有再去數據庫
注意:在spring 配置的mybatis 中不存在一級緩存,二級緩存發生增刪改,該namespace 下所有緩存數據 立即清空,目的是為了避免有臟數據存在

二、使用步驟

創建項目,導入依賴和基本編碼部分不再贅述

1.開啟二級緩存

在配置文件yml中加入以下配置
在這里插入圖片描述

代碼如下:

    cache-enabled: true #使用緩存

2.編寫ApplicationContextHolder

該類主要是為了在spring環境中獲取非spring容器管理的bean

package com.lzl.secondcache;

import org.springframework.stereotype.Component;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
/**
 * 在spring中,只要實現或者繼承xxAware接口或者類,在實例該對象時,
 * 會調用實現xxAware接口的類的方法,把參數傳遞
 */
/**
 * --效率,是成功的核心關鍵--
 * 在spring中獲取非spring管理的bean對象
 * @Author lzl
 * @Date 2023/3/9 08:00
 */
@Component
public class ApplicationContextHolder implements ApplicationContextAware {

    //spring容器
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextHolder.applicationContext = applicationContext;
    }

    public static RedisTemplate getRedisTemplate(){
        return ApplicationContextHolder.applicationContext
                .getBean("redisTemplate",RedisTemplate.class);
    }
}

3.編寫RedisCache二級緩存工具類

package com.lzl.secondcache;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 數據查詢順序:二級緩存 -> 一級緩存 -> 數據庫
 * 我們在mybatis中指定了二級緩存,在mybatis啟動會生成Cache對象,
 * 如果在該類使用@Autowired注入RedisTemplate是無法注入的,需要使用spring注入
 */
/**
 * --效率,是成功的核心關鍵--
 *
 * @Author lzl
 * @Date 2023/3/9 08:02
 */

public class RedisCache implements Cache{
    //RedisTemplate對象
    private RedisTemplate redisTemplate;

    //id相當于當前sql對應的cache的命名空間 namespace="com.qf.mapper.xxxMapper"
    private String id;

    //讀寫鎖:多線程中可以共享鎖,如果大家都是讀操作,提高數據的讀的并發能力
    //如果有一個人進行了寫操作,其他人都不能進行讀寫操作了
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    //獲取RedisTemplate對象
    public RedisTemplate getRedisTemplate(){
        //判斷
        if(redisTemplate == null){
            synchronized (RedisCache.class){
                if(redisTemplate == null){
                    RedisTemplate redisTemplate = ApplicationContextHolder.getRedisTemplate();
                    //設置key使用string類型的序列化方式
                    redisTemplate.setKeySerializer(RedisSerializer.string());
                    return redisTemplate;
                }
                return this.redisTemplate;
            }

        }
        return redisTemplate;
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return readWriteLock;
    }

    //構造器
    public RedisCache(String id) {
        System.out.println("id:"+id);
        this.id = id;
    }

    //id相當于當前sql對應的cache的命名空間
    @Override
    public String getId() {
        System.out.println("getId:"+id);
        return id;
    }

    /**
     * 將結果放入緩存,當訪問查詢方法時調用,所以這里必須通過getRedisTemplate()方法來獲取redisTemplate對象
     * @param key -> 命名空間 + sql + 參數 = 組成的字符串
     * @param value -> sql查詢的結果
     */
    @Override
    public void putObject(Object key, Object value) {
        System.out.println("putObject中的key:"+key);
        System.out.println("putObject中的value:"+value);
        getRedisTemplate().opsForValue().set(key.toString(),value);
    }

    /**
     * 獲取緩存中的數據,當訪問查詢方法時調用,所以這里必須通過getRedisTemplate()方法來獲取redisTemplate對象
     * @param key
     * @return
     */
    @Override
    public Object getObject(Object key) {
        System.out.println("getObject:"+key);
        return getRedisTemplate().opsForValue().get(key.toString());
    }

    /**
     * 從緩存中移除數據,當訪問查詢方法時調用,所以這里必須通過getRedisTemplate()方法來獲取redisTemplate對象
     * @param key
     * @return
     */
    @Override
    public Object removeObject(Object key) {
        System.out.println("removeObject:"+key);
        return getRedisTemplate().delete(key.toString());
    }

    /**
     * 清空緩存
     */
    @Override
    public void clear() {
        System.out.println("clear");
        Set keys = getRedisTemplate().keys("*" + id + "*");
        System.out.println("清空緩存keys:"+keys);
        getRedisTemplate().delete(keys);
    }

    /**
     * 獲取緩存數據長度
     * @return
     */
    @Override
    public int getSize() {
        Set keys = getRedisTemplate().keys("*" + id + "*");
        return keys.size();
    }

}

4.在mapper.xml文件中開啟全局二級緩存

    <!-- 開啟二級緩存(全局) -->
    <!--
        type:使用自定義的對象進行存儲
        blocking:true  查詢時是否阻塞加鎖
        flushInterval: 毫秒值,緩存多久清空一次
        eviction: 緩存失效策略: LRU – 最近最少使用:移除最長時間不被使用的對象。
                                FIFO – 先進先出:按對象進入緩存的順序來移除它們。
                                SOFT – 軟引用:基于垃圾回收器狀態和軟引用規則移除對象。
                                WEAK – 弱引用:更積極地基于垃圾收集器狀態和弱引用規則移除對象。
        readOnly:true 只讀,不能被修改
        size: 1024 緩存的大小
    -->
    <cache type="com.lzl.secondcache.RedisCache"/>

5.配置RedisTemplate序列化工具類,實體也需要實現序列化接口

package com.lzl.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
 * --效率,是成功的核心關鍵--
 *
 * @Author lzl
 * @Date 2023/3/9 08:05
 */
@Configuration
public class RedisConfig {

    /**
     * springboot 默認幫我們創建的RedisTemplate的key和value的序列化方式是jdk默認的方式,
     * 我們有時候手動向redis中添加的數據可能無法被查詢解析出來,所以我們需要修改序列化方式
     * @param connectionFactory
     * @return
     */

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 配置連接工廠
        redisTemplate.setConnectionFactory(connectionFactory);

        // 使用StringRedisSerializer來序列化和反序列化Redis的key值
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // 使用Jackson2JsonRedisSerializer來序列化和反序列化Redis的value值
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        // 配置對象映射器
        ObjectMapper objectMapper = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修飾符范圍。ANY指包括private和public修飾符范圍
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化輸入類型,類的信息也將添加到json中,這樣才可以根據類名反序列化。
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
        // 將對象映射器添加到序列化器中
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 配置key,value,hashKey,hashValue的序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        return redisTemplate;
    }
}

需要注意的是參數列表會報一個無法自動注入的錯誤,屬于正常現象,不影響代碼正常運行

在這里插入圖片描述

實體類需要實現序列化接口如下圖所示

在這里插入圖片描述

三、測試

首先我們先開啟Redis,這里開虛擬機太麻煩,我使用了windows版的redis

在這里插入圖片描述
在這里插入圖片描述
啟動成功

啟動項目
在這里插入圖片描述

啟動成功,測試二級緩存的基本思路是,先調用查詢的方法,查看redis中是否有緩存數據,再調用刪除的方法,再次查看查看redis中的緩存數據是否被刪除

先執行查詢
在這里插入圖片描述
查看控制臺
在這里插入圖片描述
我這里之前已經查過一次,所以直接調用了緩存,沒有執行sql語句,如果是第一次訪問,會先執行sql語句,再建立緩存
執行刪除
在這里插入圖片描述
查看控制臺
在這里插入圖片描述

刪除成功!我們再次執行查詢

在這里插入圖片描述
查看控制臺:
在這里插入圖片描述
發現執行了sql語句
再次查詢
在這里插入圖片描述
緩存命中!大功告成!


總結

本篇簡單記錄一下springboot整合mybatis使用redis做二級緩存

原文鏈接:https://blog.csdn.net/l_zl2021/article/details/129396623

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新