• RedisTemplate在项目中的应用


    如下主要通去年无聊做的 "涂涂影院后台管理系统" 一个 demo,看 RedisTemplate 的使用。

    体验地址:http://video.71xun.com:8080  账户:niceyoo 密码:123456

    主要用到地方:视频首页轮播图的获取,以及搜索检索界面,如下图所示:


    由于是非maven非springboot项目,故配置有所繁琐,但正所谓有繁才有简,在下面会带大家看一下springboot中配置redis是怎样简单。

    好了,先回到 "涂涂影院" 来吧。

    本项目环境

    开发工具:Eclipse

    JDK:1.8

    Redis;

    eclipse中截图eclipse中截图

    相信非springboot项目里的配置大家都应该很熟悉吧,主要就是配置繁琐的 xml,搭建一个 ssm 项目可参考之前的例子:SSM(Spring+SpringMVC+Mybatis)框架环境搭建

    1、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 序列化策略。

    2、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 的呢?

    1、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>

    2、yml配置信息

    spring:
      # Redis
      redis:
        host: 127.0.0.1
        password:
        # 数据库索引 默认0
        database: 0
        port: 6379
        # 超时时间 Duration类型 3秒
        timeout: 3S

    3、项目中引用

    @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

  • 相关阅读:
    dreamvc框架(一)ioc容器的集成
    1040. Longest Symmetric String (25)
    虚指针存在证明及虚函数表
    Kibana中doc与search策略的区别
    AngularJS API之bootstrap启动
    AngularJS 技术总结
    Elasticsearch Javascript API增删改查
    AngularJS 中的Promise --- $q服务详解
    Ruby编程实践
    Ruby测试小代码[计算50以内的素数]
  • 原文地址:https://www.cnblogs.com/niceyoo/p/10829002.html
Copyright © 2020-2023  润新知