RedisTemplate在項目中的應用

以下主要通去年無聊作的 "塗塗影院後臺管理系統" 一個 demo,看 RedisTemplate 的使用。html

體驗地址:http://video.71xun.com:8080  帳戶:niceyoo 密碼:123456java

主要用到地方:視頻首頁輪播圖的獲取,以及搜索檢索界面,以下圖所示:git


因爲是非maven非springboot項目,故配置有所繁瑣,但正所謂有繁纔有簡,在下面會帶你們看一下springboot中配置redis是怎樣簡單。redis

好了,先回到 "塗塗影院" 來吧。spring

本項目環境

開發工具:Eclipse數據庫

JDK:1.8緩存

Redis;springboot

eclipse中截圖eclipse中截圖

相信非springboot項目裏的配置你們都應該很熟悉吧,主要就是配置繁瑣的 xml,搭建一個 ssm 項目可參考以前的例子:SSM(Spring+SpringMVC+Mybatis)框架環境搭建微信

一、spring-redis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"
>


    <!-- 緩存的層級-->
     <context:component-scan base-package="com.jeenotes.common.cache" />

     <!-- 配置 讀取properties文件 jeenotes.properties -->
    <context:property-placeholder location="classpath:resources/jeenotes.properties"  ignore-unresolvable="true"/>

    <!-- Redis 配置 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 控制一個pool可分配多少個jedis實例 -->
        <property name="maxTotal" value="${redis.pool.maxTotal}" /><!--  -->
        <!-- 鏈接池中最多可空閒maxIdle個鏈接 ,這裏取值爲20,表示即便沒有數據庫鏈接時依然能夠保持20空閒的鏈接,
               而不被清除,隨時處於待命狀態。 -->

        <property name="maxIdle" value="${redis.pool.maxIdle}" /><!--  -->
        <!-- 最大等待時間:當沒有可用鏈接時,鏈接池等待鏈接被歸還的最大時間(以毫秒計數),超過期間則拋出異常 -->
        <property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" /><!--  -->
        <!-- 在獲取鏈接的時候檢查有效性 -->
        <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" /><!--  -->
    </bean>


    <!-- redis單節點數據庫鏈接配置 -->
    <!-- Spring-redis鏈接池管理工廠 -->  
    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.ip}" /><!--  -->
        <property name="port" value="${redis.port}" /><!--  -->
        <property name="password" value="${redis.pass}" /><!--  -->
        <property name="poolConfig" ref="jedisPoolConfig" />
    </bean> 

    <!-- redisTemplate配置,redisTemplate是對Jedis的對redis操做的擴展,有更多的操做,
           封裝使操做更便捷 -->

    <!-- SDR默認採用的序列化策略有兩種,一種是String的序列化策略,一種是JDK的序列化策略。
        StringRedisTemplate默認採用的是String的序列化策略,保存的key和value都是採用此策略序列化保存的。
        RedisTemplate默認採用的是JDK的序列化策略,保存的key和value都是採用此策略序列化保存的。
                    就是由於序列化策略的不一樣,即便是同一個key用不一樣的Template去序列化,結果是不一樣的。
                    因此根據key去刪除數據的時候就出現了刪除失敗的問題。 
     -->

    <!-- redis 序列化策略 ,一般狀況下key值採用String序列化策略, -->
    <!-- 若是不指定序列化策略,StringRedisTemplate的key和value都將採用String序列化策略; -->
    <!-- 可是RedisTemplate的key和value都將採用JDK序列化 這樣就會出現採用不一樣template保存的數據不能用同一個template刪除的問題 -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory" />
        <!-- 咱們一般所用的序列化操做:
                JDK的序列化——類上implements Serializable接口
                XML和Json
                protocol buffer(簡稱protobuf)Google的、 本項目採用中-->

        <!-- <property name="keySerializer" ref="stringRedisSerializer" />
        <property name="hashKeySerializer" ref="stringRedisSerializer" />
        <property name="valueSerializer" ref="stringRedisSerializer"/> -->


    </bean>

</beans>

註釋比較詳細,簡要概述,jedisPoolConfig 用來配置 redis 鏈接池的一些配置,JedisConnectionFactory 則做爲鏈接池的工廠類;還記得上文中提到的 redis 序列化問題嗎?上邊配置中(StringRedisTemplate)正是用到了 String 序列化策略。數據結構

二、RedisCache.java

/**
 * redis緩存
 * 
 * @author niceyoo
 *
 */

@Component
public class RedisCache {


    public final static String CAHCENAME="cache";//緩存名
    public final static int CAHCETIME=300;//默認緩存時間   以秒計算的

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public <T> boolean putCache(String key, T obj) {
        final byte[] bkey = key.getBytes();
        final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.setNX(bkey, bvalue);
            }
        });
        return result;
    }

    public <T> void putCacheWithExpireTime(String key, T obj, final long expireTime) {
        final byte[] bkey = key.getBytes();
        final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);
        redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.setEx(bkey, expireTime, bvalue);
                return true;
            }
        });
    }

    public <T> boolean putListCache(String key, List<T> objList) {
        final byte[] bkey = key.getBytes();
        final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.setNX(bkey, bvalue);
            }
        });
        return result;
    }

    public <T> boolean putListCacheWithExpireTime(String key, List<T> objList, final long expireTime) {
        final byte[] bkey = key.getBytes();
        final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.setEx(bkey, expireTime, bvalue);
                return true;
            }
        });
        return result;
    }

    public <T> getCache(final String key, Class<T> targetClass) {
        byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
            @Override
            public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.get(key.getBytes());
            }
        });
        if (result == null) {
            return null;
        }
        return ProtoStuffSerializerUtil.deserialize(result, targetClass);
    }

    public <T> List<T> getListCache(final String key, Class<T> targetClass) {
        byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
            @Override
            public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.get(key.getBytes());
            }
        });
        if (result == null) {
            return null;
        }
        return ProtoStuffSerializerUtil.deserializeList(result, targetClass);
    }

    /**
     * 精確刪除key
     * 
     * @param key
     */

    public void deleteCache(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 模糊刪除key
     * 
     * @param pattern
     */

    public void deleteCacheWithPattern(String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        redisTemplate.delete(keys);
    }

    /**
     * 清空全部緩存
     */

    public void clearCache() {
        deleteCacheWithPattern(RedisCache.CAHCENAME+"|*");
    }
}

RedisCache.java 實現了對對數據增刪改查的幾種方法,如何使用呢?

咱們以首頁的輪播圖爲例:

在須要使用的類中注入該組件:

看一下以下方法:

@ResponseBody
@RequestMapping("huandeng")
public ResultMobileBannerBean huandeng(Model model) {

    String cache_key = RedisCache.CAHCENAME + "|getPcHomeHuanDengList";
    ResultMobileBannerBean result_cache = cache.getCache(cache_key, ResultMobileBannerBean.class);

    if(result_cache != null){
        return result_cache;
    }

    ResultMobileBannerBean bannerBean = new ResultMobileBannerBean();
    bannerBean.setCode("000000");
    List<HomeBanner> homeBannerList = homeManagerService.findMobileHomeBannerList();
    bannerBean.setBannerList(homeBannerList);
    cache.putCacheWithExpireTime(cache_key, bannerBean, RedisCache.CAHCETIME);

    return bannerBean;
}

主要是 ResultMobileBannerBean result_cache = cache.getCache(cache_key, ResultMobileBannerBean.class); 在去數據庫請求數據以前,先去 redis 中讀取緩存信息,若是返回的數據非空的話,則返回該數據,不然去數據庫查詢數據,查詢後在存放在 redis 中。

項目源碼:https://gitee.com/niceyoo/jeenotes-ssm.git


springboot 中是如何引用 redis 的呢?

一、maven依賴

<!-- Redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-redis</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
<!-- Gson 可暫時忽略-->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
</dependency>

二、yml配置信息

spring:
  # Redis
  redis:
    host: 127.0.0.1
    password:
    # 數據庫索引 默認0
    database: 0
    port: 6379
    # 超時時間 Duration類型 3秒
    timeout: 3S

三、項目中引用

@Autowired
private StringRedisTemplate redisTemplate;

@RequestMapping(value = "/getByParentId/{parentId}", method = RequestMethod.GET)
@ApiOperation(value = "經過parentId獲取")
public Result<List<Department>> getByParentId(@PathVariable String parentId,
                                              @ApiParam("是否開始數據權限過濾"@RequestParam(required = false, defaultValue = "true") Boolean openDataFilter){

    List<Department> list = new ArrayList<>();
    User u = securityUtil.getCurrUser();
    String key = "department::"+parentId+":"+u.getId()+"_"+openDataFilter;
    String v = redisTemplate.opsForValue().get(key);
    if(StrUtil.isNotBlank(v)){
        list = new Gson().fromJson(v, new TypeToken<List<Department>>(){}.getType());
        return new ResultUtil<List<Department>>().setData(list);
    }
    list = departmentService.findByParentIdOrderBySortOrder(parentId, openDataFilter);
    list = setInfo(list);
    redisTemplate.opsForValue().set(key,
            new GsonBuilder().registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY).create().toJson(list));
    return new ResultUtil<List<Department>>().setData(list);
}

RedisTemplate 定義了 5 種數據結構操做:

  1. redisTemplate.opsForValue();//操做字符串
  2. redisTemplate.opsForHash();//操做hash
  3. redisTemplate.opsForList();//操做list
  4. redisTemplate.opsForSet();//操做set
  5. redisTemplate.opsForZSet();//操做有序set

最優補充

從上文可看出 RedisTemplate 在 springboot 中應用尤其簡單,因此趕快切到 springboot 中吧~

若是文章有錯的地方歡迎指正,你們互相留言交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:niceyoo

相關文章
相關標籤/搜索