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

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

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


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

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

本项目环境

开发工具:Eclipse

JDK:1.8

Redis;

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

RedisTemplate在项目中的应用的更多相关文章

  1. spring3.0结合Redis在项目中的运用

    推荐一个程序员的论坛网站:http://ourcoders.com/home/ 以下内容使用到的技术有:Redis缓存.SpringMVC.Maven.项目中使用了redis缓存,目的是在业务场景中, ...

  2. Spring + SpringMVC + Mybatis项目中redis的配置及使用

    maven文件 <!-- redis --> <dependency> <groupId>redis.clients</groupId> <art ...

  3. Spring-Boot项目中配置redis注解缓存

    Spring-Boot项目中配置redis注解缓存 在pom中添加redis缓存支持依赖 <dependency> <groupId>org.springframework.b ...

  4. VS项目中使用Nuget还原包后编译生产还一直报错?

    Nuget官网下载Nuget项目包的命令地址:https://www.nuget.org/packages 今天就遇到一个比较奇葩的问题,折腾了很久终于搞定了: 问题是这样的:我的解决方案原本是好好的 ...

  5. ABP项目中使用Swagger生成动态WebAPI

    本文是根据角落的白板报的<使用ABP实现SwaggerUI,生成动态webapi>一文的学习总结,感谢原文作者角落的白板报. 1 安装Swashbuckle.core 1.1 选择WebA ...

  6. iOS 之项目中遇到的问题总结

    昨天去一家公司面试,面试官问了我在项目开发中遇到过哪些问题,是什么引起的,怎样解决的? 当时由于有点小紧张只说出了一两点,现在就来好好总结一下. 问题: 1.两表联动 所谓的两表联动就是有左右两个表格 ...

  7. My97DatePicker时间控件在项目中的应用

    一.下载My97DatePicker的压缩包My97DatePicker.rar,解压. 注:My97DatePicker最新版本有开发包,项目中使用时删掉,以便节省空间,提高程序的运行效率. 二.在 ...

  8. 在项目中同时使用Objective-C和Swift

    苹果发布的Swift语言可以和之前的Objective-C语言同时存在于一个项目中. 可能有人会认为是同一个类文件中既可以有Objective-C也可以有Swift,这是不对的.同一个类文件或同一个代 ...

  9. 在数据库访问项目中使用微软企业库Enterprise Library,实现多种数据库的支持

    在我们开发很多项目中,数据访问都是必不可少的,有的需要访问Oracle.SQLServer.Mysql这些常规的数据库,也有可能访问SQLite.Access,或者一些我们可能不常用的PostgreS ...

随机推荐

  1. Python实现堆

    堆 (heap) 是一种经过排序的完全二叉树,其中任一非叶子节点的值均不大于(或不小于)其左孩子和右孩子节点的值. 注:定义来自百度百科. 堆,又被为优先队列(priority queue).尽管名为 ...

  2. Java基础教程(26)--反射

    一.类   对于每一种类型的对象,Java虚拟机都会实例化一个java.lang.Class类的不可变实例.该实例提供了获取对象的运行时属性的方法,包括它的成员和类型信息.Class类还提供了创建新实 ...

  3. PAT甲级1006水题飘过

    题目分析:由于不存在相同的两个时间(24:00:00和00:00:00不会同时存在),则我们假设两个全局变量存放到达的最早的时间和达到的最晚的时间,设置最早的初值为“23:59:59”,设置最晚的初值 ...

  4. sizeof运算符和strlen()函数

    首先放上代码和运行结果.(在VC6.0上运行) #include<stdio.h> #include<string.h> int main(void) { char s1[]= ...

  5. C++错题记录

    D. 通俗讲 , 前置++ : 先自增,再赋值    后置++: 先赋值,再自增 从反汇编中,可以看出: 前置++效率比后置++高 前置++: 自增后返回引用   后置++: 拷贝一份临时变量,再自增 ...

  6. Linux 服务器管理建议

    Linux 服务器管理建议 一.学习Linux 的注意事项 Linux 严格区分大小写 Linux 一切皆文件 Linux 不靠扩展名区分文件类型 靠权限位标识来确定的 特殊文件要求写扩展名(给管理员 ...

  7. sql server 压缩日志文件

    USE [master] GO ALTER DATABASE TestDB SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE TestDB SET ...

  8. C#泛型集合之——队列与堆栈

    队列与堆栈基础 队列 1.操作: (1)创建及初始化: Queue<类型> 队列名 =new Queue<类型>()://空队列,无元素 Queue<类型> 队列名 ...

  9. 2019 浪潮java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.浪潮等公司offer,岗位是Java后端开发,因为发展原因最终选择去了浪潮,入职一年时间了,之前面试了很多家公 ...

  10. 【面试突击】- 2019年125条常见的java面试笔试题汇总(一)

    1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部 问题,而只是选择其中的一部分,暂时不用部分细节.抽象包括两个方面,一是过程抽象,二 ...