SSM下Mybatis使用Redis作爲二級緩存

Mybatis使用Redis作爲二級緩存

  1. SSM整合在這裏不在闡述了,可以看我另一篇帖子、裏邊也集成了redis、quartz等

  2. git地址:ssm+redis+quartz
    博客地址:ssm blog

  3. 框架整合之後,我們直接上代碼使用redis作爲mybatis的二級緩存

  4. 首先我們在pom.xml添加依賴commons-codec,我們使用裏邊的一個方法,按照一定的規則生成key

 	DigestUtils.md5Hex(key)
	<common-codec.version>1.12</common-codec.version>
	<dependency>
    <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>${common-codec.version}</version>
    </dependency>
  1. 我們新建一個類實現Cache接口,重寫裏邊的方法
	package com.bootdu.redis;
	
	import org.apache.commons.codec.digest.DigestUtils;
	import org.apache.ibatis.cache.Cache;
	import org.slf4j.Logger;
	import org.slf4j.LoggerFactory;
	import org.springframework.data.redis.core.RedisTemplate;
	import org.springframework.data.redis.core.ValueOperations;
	
	import java.util.Set;
	import java.util.concurrent.TimeUnit;
	import java.util.concurrent.locks.ReadWriteLock;
	import java.util.concurrent.locks.ReentrantReadWriteLock;
	
	/**
	 * 使用Redis緩存作爲Mybatis二級緩存
	 */
	public class RedisCache implements Cache {
	    //slf4j的日誌記錄器
	    private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);
	    //緩存對象唯一標識
	    private final String id; //orm的框架都是按對象的方式緩存,而每個對象都需要一個唯一標識.
	    //用於事務性緩存操作的讀寫鎖
	    private static ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); //處理事務性緩存中做的
	    //操作數據緩存的--跟着線程走的
	    public static RedisTemplate redisTemplate;  //Redis的模板負責將緩存對象寫到redis服務器裏面去
	    //緩存對象的是失效時間,60分鐘
	    private static final long EXPRIRE_TIME_IN_MINUT = 60;
	    //生成key
	    private final String COMMON_CACHE_KEY = "com:bootdu:";
	
	    /**
	     * 所有key
	     */
	    private String getKeys() {
	        return COMMON_CACHE_KEY + this.id + ":*";
	    }
	
	    /**
	     * 按照一定規則標識key
	     */
	    private Object getKey(Object key) {
	        return COMMON_CACHE_KEY + this.id + ":" + DigestUtils.md5Hex(String.valueOf(key));
	    }
	
	    public static void setRedisTemplate(RedisTemplate redisTemplate) {
	        RedisCache.redisTemplate = redisTemplate;
	    }
	
	    //構造方法---把對象唯一標識傳進來
	    public RedisCache(String id) {
	        if (id == null) {
	            throw new IllegalArgumentException("緩存對象id是不能爲空的");
	        }
	        this.id = id;
	    }
	
	    @Override
	    public String getId() {
	        return this.id;
	    }
	
	    //給模板對象RedisTemplate賦值,並傳出去
	    public RedisTemplate getRedisTemplate() {
	        return redisTemplate;
	    }
	
	    /*
	     *保存緩存對象的方法
	     */
	    @Override
	    public void putObject(Object key, Object value) {
	        try {
	            RedisTemplate redisTemplate = getRedisTemplate();
	            //使用redisTemplate得到值操作對象
	            ValueOperations operation = redisTemplate.opsForValue();
	            //使用值操作對象operation設置緩存對象
	            operation.set(getKey(key), value, EXPRIRE_TIME_IN_MINUT, TimeUnit.MINUTES);  //TimeUnit.MINUTES系統當前時間的分鐘數
	            logger.debug("緩存對象保存成功,key{}", getKey(key));
	        } catch (Throwable t) {
	            logger.error("緩存對象保存失敗" + t, getKey(key));
	        }
	    }
	
	    /*
	     *獲取緩存對象的方法
	     */
	    @Override
	    public Object getObject(Object key) {
	        try {
	            RedisTemplate redisTemplate = getRedisTemplate();
	            ValueOperations operations = redisTemplate.opsForValue();
	            Object result = operations.get(getKey(key));
	            logger.debug("獲取緩存對象", getKey(key));
	            return result;
	        } catch (Throwable t) {
	            logger.error("緩存對象獲取失敗" + t, getKey(key));
	            return null;
	        }
	    }
	
	    /*
	        刪除緩存對象
	     */
	    @Override
	    public Object removeObject(Object key) {
	        try {
	            RedisTemplate redisTemplate = getRedisTemplate();
	            redisTemplate.delete(getKey(key));
	            logger.debug("刪除緩存對象成功!", getKey(key));
	        } catch (Throwable t) {
	            logger.error("刪除緩存對象失敗!" + t, getKey(key));
	        }
	        return null;
	    }
	
	    /*
	        清空緩存對象
	        當緩存的對象更新了的化,就執行此方法
	     */
	    @Override
	    public void clear() {
	        RedisTemplate redisTemplate = getRedisTemplate();
	        //回調函數
	        Set<String> keys = redisTemplate.keys(getKeys());
	        redisTemplate.delete(keys);
	        logger.debug("清空緩存對象成功!", keys);
	    }
	
	    //可選實現的方法
	    @Override
	    public int getSize() {
	        return 0;
	    }
	
	    @Override
	    public ReadWriteLock getReadWriteLock() {
	        return readWriteLock;
	    }
	}

6.我們要使用一個RedisTemplate,然後將它注入到我們上邊的類,在redis.xml配置文件種配置

   <bean id="stringRedisSerializer"
	          class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
   <bean id="redisTemplate_mybatis" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="redisConnectionFactory"></property>
        <property name="keySerializer" ref="stringRedisSerializer"></property>
        <property name="valueSerializer">
            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
        </property>
    </bean>

7.我們構造一個類去注入redisTemplate

	package com.bootdu.redis;
	
	import org.springframework.data.redis.core.RedisTemplate;
	
	/**
	 * 構造一個RedisTemplate注入
	 */
	public class MybatisRedisCacheTransfer {
	
	    public void setRedisTemplate(RedisTemplate redisTemplate) {
	        RedisCache.setRedisTemplate(redisTemplate);
	    }
	
	}
----------------------------------------------------------------------
redis.xml 將redisTemplate_mybatis 注入到這裏
	<!--注入-->
    <bean class="com.bootdu.redis.MybatisRedisCacheTransfer">
        <property name="redisTemplate" ref="redisTemplate_mybatis"></property>
    </bean>

在這裏插入圖片描述在這裏插入圖片描述

  1. 我們在需要使用緩存的接口對應的mapper.xml種配置這個緩存實現類
	<!--使用Redis緩存作爲MyBatis二級緩存-->
    <cache type="com.bootdu.redis.RedisCache"/>

在這裏插入圖片描述

  1. 測試:頁面可以請求到
    在這裏插入圖片描述
    我們看下控制檯:第一請求進來的時候,我們看到,在緩存中沒有找到執行了查詢,然後並緩存到redis裏邊
    在這裏插入圖片描述
    在這裏插入圖片描述
    我們刷新請求下,再看控制檯:
    在這裏插入圖片描述
    這次沒有sql執行 而是直接去了緩存種查詢了,看到這樣,就成功了

至此我們整合redis作爲mybatis二級緩存已經完成了,思路:

1:創建一個類實現Mybatis Cache接口,重寫裏邊的方法
2:構造一個RedisTemplate 注入RedisTemplate
3:在mapper接口對應的xml文件種配置標籤,type寫我們Cache接口的實現類
Ps:注意,我們實體Po一定要實現序列化接口,不然在反序列化的時候要抱異常

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章