Spring Boot集成redis

2022-08-17 12:59:17

1.1 简介

REmote DIctionary Server(Redis)是一个由Salvatore Sanfilippo写的key-value存储系统。

Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API

它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets)和 有序集合(sorted sets)等类型。

reids的优点

  • 异常快 -Redis非常快,每秒可执行大约110000次的设置(SET)操作,每秒大约可执行81000次的读取/获取(GET)操作。
  • 支持丰富的数据类型 -Redis支持开发人员常用的大多数数据类型,例如列表,集合,排序集和散列等等。这使得Redis很容易被用来解决各种问题,因为我们知道哪些问题可以更好使用地哪些数据类型来处理解决。
  • 操作具有原子性 - 所有Redis操作都是原子操作,这确保如果两个客户端并发访问,Redis服务器能接收更新的值。
  • 多实用工具 -Redis是一个多实用工具,可用于多种用例,如:缓存,消息队列(Redis本地支持发布/订阅),应用程序中的任何短期数据,例如,web应用程序中的会话,网页命中计数等。

1.2Redis 安装

1.2.1Linux安装

本课程是在vmvare 虚拟机中来安装的redis (centos 7),学习的时候如果有自己的阿里云服务器,也可以在阿里云中来安装redis,都可以。只要能ping 的通云主机或者虚拟机的ip,然后在虚拟机或者云主机中放行对应的端口(或者关掉防火墙)即可访问redis。下面来介绍一下redis 的安装过程:

1.2.1.1 安装gcc 编译

因为后面安装redis的时候需要编译,所以事先得先安装gcc编译。阿里云主机已经默认安装了gcc,如果是自己安装的虚拟机,那么需要先安装一下gcc

yum install gcc-c++

1.2.1.2 下载redis

有两种方式下载安装包,一种是去官网上下载(https://redis.io),然后将安装包拷到centos中,另种方法是直接使用wget来下载:

wget http://download.redis.io/releases/redis-3.2.8.tar.gz

如果没有安装过wget,可以通过如下命令安装:

yum install wget

1.2.1.3 解压安装

解压安装包:

tar –vzxf redis-3.2.8.tar.gz

然后将解压的文件夹redis-3.2.8放到/usr/local/下,一般安装软件都放在/usr/local下。然后进入/usr/local/redis-3.2.8/文件夹下,执行make 命令即可完成安装。
【注】如果make失败,可以尝试如下命令:

make MALLOC=libc
make install

1.2.1.4 修改配置文件

安装成功之后,需要修改一下配置文件,包括允许接入的ip,允许后台执行,设置密码等等。
打开redis配置文件:vi redis.conf
在命令模式下输入/bind来查找bind配置,按n来查找下一个,找到配置后,将bind配置成0.0.0.0,允许任意服务器来访问redis,即:

bind0.0.0.0

使用同样的方法,将daemonize改成yes(默认为no),允许redis在后台执行。
requirepass注释打开,并设置密码为123456(密码自己设置)。

1.2.1.5 启动redis

redis-3.2.8目录下,指定刚刚修改好的配置文件redis.conf来启动redis

redis-server./redis.conf

再启动redis 客户端:

redis-cli

由于我们设置了密码,在启动客户端之后,输入auth 123456即可登录进入客户端。
然后我们来测试一下,往redis中插入一个数据:

set name CSDN

然后来获取name

get name

如果正常获取到CSDN,则说明没有问题。

1.2.2Windows安装

下载地址:https://github.com/MSOpenTech/redis/releases
Redis 支持32位和64位。这个需要根据你系统平台的实际情况选择,这里我们下载Redis-x64-xxx.zip压缩包到C盘,解压后,将文件夹重新命名为redis

打开一个cmd窗口 使用cd命令切换目录到C:\redis
运行redis-server.exe redis.windows.conf
如果想方便的话,可以把redis的路径加到系统的环境变量里,这样就省得再输路径了,后面的那个redis.windows.conf可以省略,如果省略,会启用默认的。输入之后,会显示如下界面:
在这里插入图片描述

1.3 集成redis

Spring Bootredis的支持已经非常完善了,丰富的api 已经足够我们日常的开发。

有两个redis模板:RedisTemplateStringRedisTemplate
RedisTemplate提供给我们操作对象,操作对象的时候,我们通常是以json 格式存储,但在存储的时候,会使用Redis默认的内部序列化器;导致我们存进里面的是乱码之类的东西。当然了,我们可以自己定义序列化。
StringRedisTemplate主要给我们提供字符串操作,我们可以将实体类等转成json 字符串即可,在取出来后,也可以转成相应的对象,所以很有必要导入fastjson 的原因。

1.3.1 添加依赖

  • 如果你的spring boot的版本号是1.4.01.5.0之间,添加redisjar包的时候 添加成spring-boot-starter-data-redisspring-boot-starter-redis 都是都可以的。
  • 但是如果你的spring boot的版本号 是1.4.0以前 也就是1.3.8 版本以前,添加redisjar包 就必须是spring-boot-starter-redisjar包。
  • 如果你的spring boot的版本号在1.5.0以后的,添加redisjar包就必须是spring-boot-starter-data-redis

1.3.2SpringBoot 1.4 整合redis

1.3.2.1 依赖

采用的是spring-boot-starter-redis,也可以添加成spring-boot-starter-data-redis

<!--集成redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-redis</artifactId><version>1.4.1.RELEASE</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.3</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency>

1.3.2.2 添加配置

spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码(默认为空)
spring.redis.password=
#连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.pool.max-idle=8
#连接池中的最小空闲连接
spring.redis.pool.min-idle=0
#连接超时时间(毫秒)
spring.redis.timeout=30000

1.3.2.3 配置类RedisConfig

@RefreshScope
动态配置刷新的我们要配置一个@RefreshScope在类上才可以实现对象属性的的动态更新。
我们来总结下@RefreshScope实现流程

1、需要动态刷新的类标注@RefreshScope 注解
2、@RefreshScope 注解标注了@Scope注解,并默认了ScopedProxyMode.TARGET_CLASS; 属性,此属性的功能就是在创建一个代理,在每次调用的时候都用它来调用GenericScope get方法来获取对象
3、如属性发生变更会调用ContextRefresher refresh() -》RefreshScope refreshAll()进行缓存清理方法调用,并发送刷新事件通知 -》GenericScope真正的 清理方法destroy()实现清理缓存
4、在下一次使用对象的时候,会调用GenericScope get(String name, ObjectFactory<?> objectFactory)方法创建一个新的对象,并存入缓存中,此时新对象因为Spring的装配机制就是新的属性了。

@Configuration@EnableCaching@RefreshScopepublicclassRedisConfigextendsCachingConfigurerSupport{@Value("${spring.redis.host}")privateString host;@Value("${spring.redis.port}")privateint port;@Value("${spring.redis.timeout}")privateint timeout;@Value("${spring.redis.password}")privateString password;@Value("${spring.redis.pool.max-active}")privateint maxActive;@Value("${spring.redis.pool.max-wait}")privateint maxWait;@Value("${spring.redis.pool.max-idle}")privateint maxIdle;@Value("${spring.redis.pool.min-idle}")privateint minIdle;@RefreshScope@BeanpublicKeyGeneratorwiselyKeyGenerator(){returnnewKeyGenerator(){@OverridepublicObjectgenerate(Object target,Method method,Object... params){StringBuilder sb=newStringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());for(Object obj: params){
                    sb.append(obj.toString());}return sb.toString();}};}@RefreshScope@BeanpublicJedisConnectionFactoryredisConnectionFactory(){JedisConnectionFactory factory=newJedisConnectionFactory();
        factory.setHostName(host);
        factory.setPort(port);
        factory.setTimeout(timeout);//设置连接超时时间
        factory.setPassword(password);
        factory.getPoolConfig().setMaxIdle(maxIdle);
        factory.getPoolConfig().setMinIdle(minIdle);
        factory.getPoolConfig().setMaxTotal(maxActive);
        factory.getPoolConfig().setMaxWaitMillis(maxWait);return factory;}@RefreshScope@BeanpublicCacheManagercacheManager(RedisTemplate redisTemplate){RedisCacheManager cacheManager=newRedisCacheManager(redisTemplate);// Number of seconds before expiration. Defaults to unlimited (0)
        cacheManager.setDefaultExpiration(10);//设置key-value超时时间return cacheManager;}@RefreshScope@BeanpublicRedisTemplate<String,String>redisTemplate(RedisConnectionFactory factory){StringRedisTemplate template=newStringRedisTemplate(factory);setSerializer(template);//设置序列化工具,这样ReportBean不需要实现Serializable接口
        template.afterPropertiesSet();return template;}@RefreshScopeprivatevoidsetSerializer(StringRedisTemplate template){Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=newJackson2JsonRedisSerializer(Object.class);ObjectMapper om=newObjectMapper();
        om.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);}}

1.3.2.4RedisUtils

importjava.io.Serializable;importjava.util.List;importjava.util.Set;importjava.util.concurrent.TimeUnit;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.HashOperations;importorg.springframework.data.redis.core.ListOperations;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.core.SetOperations;importorg.springframework.data.redis.core.ValueOperations;importorg.springframework.data.redis.core.ZSetOperations;importorg.springframework.stereotype.Service;@ServicepublicclassRedisUtils{@AutowiredprivateRedisTemplate redisTemplate;/**
     * 写入缓存
     * @param key
     * @param value
     * @return
     */publicbooleanset(finalString key,Object value){boolean result=false;try{ValueOperations<Serializable,Object> operations= redisTemplate.opsForValue();
            operations.set(key, value);
            result=true;}catch(Exception e){
            e.printStackTrace();}return result;}/**
     * 写入缓存设置时效时间
     * @param key
     * @param value
     * @return
     */publicbooleanset(finalString key,Object value,Long expireTime,TimeUnit timeUnit){boolean result=false;try{ValueOperations<Serializable,Object> operations= redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, timeUnit);
            result=true;}catch(Exception e){
            e.printStackTrace();}return result;}/**
     * 批量删除对应的value
     * @param keys
     */publicvoidremove(finalString... keys){for(String key: keys){remove(key);}}/**
     * 批量删除key
     * @param pattern
     */publicvoidremovePattern(finalString pattern){Set<Serializable> keys= redisTemplate.keys(pattern);if(keys.size()>0){
            redisTemplate.delete(keys);}}/**
     * 删除对应的value
     * @param key
     */publicvoidremove(finalString key){if(exists(key)){
            redisTemplate.delete(key);}}/**
     * 判断缓存中是否有对应的value
     * @param key
     * @return
     */publicbooleanexists(finalString key){return redisTemplate.hasKey(key);}/**
     * 读取缓存
     * @param key
     * @return
     */publicObjectget(finalString key){Object result=null;ValueOperations<Serializable,Object> operations= redisTemplate.opsForValue();
        result= operations.get(key);return result;}/**
     * 哈希 添加
     * @param key
     * @param hashKey
     * @param value
     */publicvoidhmSet(String key,Object hashKey,Object value){HashOperations<String,Object,Object> hash= redisTemplate.opsForHash();
        hash.put(key,hashKey,value);}/**
     * 哈希获取数据
     * @param key
     * @param hashKey
     * @return
     */publicObjecthmGet(String key,Object hashKey){HashOperations<String,Object,Object>  hash= redisTemplate.opsForHash();return hash.get(key,hashKey);}/**
     * 列表添加
     * @param k
     * @param v
     */publicvoidlPush(String k,Object v){ListOperations<String,Object> list= redisTemplate.opsForList();
        list.rightPush(k,v);}/**
     * 列表获取
     * @param k
     * @param l
     * @param l1
     * @return
     */publicList<Object>lRange(String k,long l,long l1){ListOperations<String,Object> list= redisTemplate.opsForList();return list.range(k,l,l1);}/**
     * 集合添加
     * @param key
     * @param value
     */publicvoidadd(String key,Object value){SetOperations<String,Object> set= redisTemplate.opsForSet();
        set.add(key,value);}/**
     * 集合获取
     * @param key
     * @return
     */publicSet<Object>setMembers(String key){SetOperations<String,Object> set= redisTemplate.opsForSet();return set.members(key);}/**
     * 有序集合添加
     * @param key
     * @param value
     * @param scoure
     */publicvoidzAdd(String key,Object value,double scoure){ZSetOperations<String,Object> zset= redisTemplate.opsForZSet();
        zset.add(key,value,scoure);}/**
     * 有序集合获取
     * @param key
     * @param scoure
     * @param scoure1
     * @return
     */publicSet<Object>rangeByScore(String key,double scoure,double scoure1){ZSetOperations<String,Object> zset= redisTemplate.opsForZSet();return zset.rangeByScore(key, scoure, scoure1);}

1.3.2.5 测试controller

@RestControllerpublicclassSpringBootController{publicstaticfinalLogger log=LoggerFactory.getLogger(SpringBootController.class);@AutowiredTestService testService;@AutowiredprivateRedisUtils redisUtils;@RequestMapping(value="/hello/{id}")publicStringhello(@PathVariable(value="id")String id){//查询缓存中是否存在boolean hasKey= redisUtils.exists(id);String str="";if(hasKey){//获取缓存Object object=  redisUtils.get(id);
            log.info("从缓存获取的数据"+ object);
            str= object.toString();}else{//从数据库中获取信息
            log.info("从数据库中获取数据");
            str
  • 作者:sunnyday0426
  • 原文链接:https://blog.csdn.net/weixin_42039228/article/details/123476084
    更新时间:2022-08-17 12:59:17