linux下安装Redis最新版本,搭建多哨兵,搭建分布式Cluster集群,springboot2.x集成和封装

本文详细介绍了Redis的安装步骤、多哨兵模式的配置、集群的搭建与管理,包括集群的扩容与缩容操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.Redis安装

1.1.下载并解压Redis linux版本

1.2.安装C++ 环境

1.3.安装redis

1.4.设置开机自启动

2.Redis多哨兵模式

3.Redis Cluster集群

3.1.安装Ruby环境(redis版本<5.xxx)

3.2.安装ruby脚本运行所需的依赖包gem(redis版本<5.xxx)

3.3.设置6个实例配置文件并脚本启动

3.4.创建集群

3.5.集群扩容

3.6.集群缩容

4.springboot2.x的集成和工具类封装

4.1.引入pom.xml文件maven依赖包

4.2.配置文件application.properties

4.3.重写redisTemplate

4.4.封装Redis工具类

4.5.写个测试类测试


1.Redis安装

1.1.下载并解压Redis linux版本

在redis官网下载最新的版本,我这里是6.0.6版本,http://download.redis.io/releases/redis-6.0.6.tar.gz,一般上传到/opt目录下

解压redis-6.0.6.tar.gz:

tar -zxvf redis-6.0.6.tar.gz

1.2.安装C++ 环境

#安装gcc套装(如果是新系统gcc通常安装不全面)
yum install -y cpp binutils glibc glibc-kernheaders glibc-common glibc-devel gcc make 
#升级gcc
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
#设置永久升级(选做)
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile

1.3.安装redis

1.进入目录/opt/redis/redis-6.0.6/下,执行

make
#默认安装到了/usr/local/bin下,也可以通过PREFIX来指定安装目录
make install或者make install PREFIX=/usr/local/redis

redis的默认安装路径在/usr/local/bin下

2.拷贝redis.conf到/usr/local/bin下

cd /usr/local/bin
mkdir config
cp /opt/redis/redis-6.0.6/redis.conf config/

3.修改配置文件redis.conf中的daemonize yes,启动挂到后台

启动redis命令:

redis-server config/redis.conf

连接redis命令

#查看redis服务是否开启
ps -ef|grep redis
#连接redis服务
redis-cli -p 6379
#退出redis-cli
exit
#关闭redis-server
shutdown

1.4.设置开机自启动

1. 拷贝redis源码包中的启动脚本到/etc/init.d下,可以顺便起个名字叫redis

cp /opt/redis/redis-6.0.6/utils/redis_init_script /etc/init.d/redis

2.有兴趣可以读一下这个启动脚本,关键的地方检查一下,一个是服务端路径(EXEC和CLIEXEC),一个是CONF的配置文件路径,叫6379.conf

所以需要接着拷贝配置文件

#创建文件夹redis
cd /etc
mkdir redis
#从源码出拷贝配置文件,并修改文件名称成6379.conf
cp /opt/redis/redis-6.0.6/redis.conf /etc/redis/6379.conf

这里也可以修改6379.conf文件的内容,比如注释掉bind 127.0.0.1,protected-mode no等等

3.开机自启动设置

#添加redis服务
chkconfig --add redis
#设为开机启动
chkconfig redis on
#常用命令
service redis start
service redis stop

如果提示service redis does not support chkconfig,做如下操作

使用vim编辑redis-toutou文件,在第一行加入如下两行注释,保存退出

# chkconfig: 2345 90 10

# description: Redis is a persistent key-value database

注释的意思是,redis服务必须在运行级2,3,4,5下被启动或关闭,启动的优先级是90,关闭的优先级是10。

再次执行开机自启命令。chkconfig redis on

2.Redis多哨兵模式

概述

Redis-Sentinel是官方推荐的高可用解决方案,当redis在做master-slave的高可用方案时,假如master宕机了,redis本身(以及其很多客户端)都没有实现自动进行主备切换,而redis-sentinel本身也是独立运行的进程,可以部署在其他与redis集群可通讯的机器中监控redis集群。

工作机制

Redis提供了sentinel(哨兵)机制,通过sentinel模式启动redis后,自动监控master/slave的运行状态,基本原理是:心跳机制+投票裁决 。每个sentinel会向其它sentinal、master、slave定时发送消息,以确认对方是否“活”着,如果发现对方在指定时间(可配置)内未回应,则暂时认为对方已挂(所谓的“主观认为宕机” Subjective Down,简称SDOWN)。

若”哨兵群”中的多数sentinel,都报告某一master没响应,系统才认为该master”彻底死亡”(即:客观上的真正down机,Objective Down,简称ODOWN),通过一定的vote算法,从剩下的slave节点中,选一台提升为master,然后自动修改相关配置

哨兵模式是建立在主从复制+读写分离集群的基础上的,多了一个独立的哨兵进程,用于监控主节点和从节点的Redis

#切换到工作目录下
cd cd /usr/local/bin/
mkdir redis-sentinel
#从源码复制3个redis.conf配置文件以及3个哨兵配置文件sentinel.conf,并用不同的端口号命名
#其中6379是master,6380和6381是slave
cp /opt/redis/redis-6.0.6/redis.conf /usr/local/bin/redis-sentinel/redis6379.conf
cp /opt/redis/redis-6.0.6/redis.conf /usr/local/bin/redis-sentinel/redis6380.conf
cp /opt/redis/redis-6.0.6/redis.conf /usr/local/bin/redis-sentinel/redis6381.conf

cp /opt/redis/redis-6.0.6/sentinel.conf /usr/local/bin/redis-sentinel/sentinel26379.conf
cp /opt/redis/redis-6.0.6/sentinel.conf /usr/local/bin/redis-sentinel/sentinel26380.conf
cp /opt/redis/redis-6.0.6/sentinel.conf /usr/local/bin/redis-sentinel/sentinel26381.conf

依次修改新拷贝的3个redis.conf文件内容,注意端口

daemonize yes
pidfile /var/run/redis_6379.pid
port 6379
# bind 127.0.0.1  可选,默认就处理所有请求。
logfile "./redis-6379.log"
dir "/usr/local/bin/redis-sentinel/"
#redis配置密码的话,需要以下配置
#masterauth "123456"
#requirepass "123456"

依次修改新拷贝的3个sentinel.conf文件内容,注意端口

daemonize yes 
port 26379
#指定工作目录
dir "/usr/local/bin/redis-sentinel"
logfile "./sentinel26379.log" 
#指定别名  主节点地址  端口  哨兵个数(有几个哨兵监控到主节点宕机执行转移)
sentinel monitor mymaster 127.0.0.1 6379 2
#如果哨兵3s内没有收到主节点的心跳,哨兵就认为主节点宕机了,默认是30秒  
sentinel down-after-milliseconds mymaster 3000
#选举出新的主节点之后,可以同时连接从节点的个数
sentinel parallel-syncs mymaster 1
#如果10秒后,master仍没活过来,则启动failover,默认180s  
sentinel failover-timeout mymaster 10000 
#配置连接redis主节点密码,有就配置,没有就忽略
#sentinel auth-pass mymaster 123456

分别启动3个redis实例,改变主从关系,启动3个sentinel实例

#切换到工作路径,启动3个redis实例
cd /usr/local/bin
redis-server /usr/local/bin/redis-sentinel/redis6379.conf
redis-server /usr/local/bin/redis-sentinel/redis6380.conf
redis-server /usr/local/bin/redis-sentinel/redis6381.conf
#动态改变主从关系,成为6379的slave
redis-cli -p 6380
slaveof 127.0.0.1 6379
#检查一下是否是slave
info replication
exit

redis-cli -p 6380
slaveof 127.0.0.1 6379
#检查一下是否是slave
info replication
exit

redis-cli -p 6381
slaveof 127.0.0.1 6379
#检查一下是否是slave
info replication
exit

#查看主从关系
redis-cli -p 6379
#检查一下是否是master,2个slave
info replication
exit

#启动3个sentinel实例
redis-sentinel /usr/local/bin/redis-sentinel/sentinel26379.conf
redis-sentinel /usr/local/bin/redis-sentinel/sentinel26380.conf
redis-sentinel /usr/local/bin/redis-sentinel/sentinel26381.conf

3.Redis Cluster集群

Redis哨兵模式不能动态扩充,到Redis3.x之后,提出了cluster集群模式。

Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

结构特点

结构特点:
1、所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
2、节点的fail是通过集群中超过半数的节点检测失效时才生效。
3、客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
4、redis-cluster把所有的物理节点映射到[0-16383]哈希槽上(不一定是平均分配),cluster 负责维护node<->哈希槽<->value。
5、Redis集群预分好16384个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个哈希槽中

例如3个节点的Redis:

  • 节点A覆盖0-5460;

  • 节点B覆盖5461-10922;

  • 节点C覆盖10923-16383.

由于redis-cluster采用投票容错的方式来判断该节点是否挂掉,投票容错简单点说就是投票超总数的一半即判定该节点挂掉,因此最少需要三个节点,但是由于redis-cluster要保证高可用,因此每个主节点需要一个备份机,也就是说至少需要六个节点

 

redis版本>=5.xxx,直接使用 ./redis-cli --cluster create 指令构建redis集群。

redis版本<5.xxx,需要安装ruby、rubygems环境,使用 ./redis-trib.rb create 指令构建redis集群,

请注意你的redis版本,redis版本>=5.xxx,不需要执行3.1和3.2操作

3.1.安装Ruby环境(redis版本<5.xxx)

# 安装基本工具
yum -y install ruby ruby-devel rubygems rpm-build
# 查看ruby版本,一般都是版本太低,至少需要2.3以上
ruby -v
#ruby 2.0.0p648 (2015-12-16) [x86_64-linux]

# 安装yum源
yum install -y centos-release-scl-rh
# 安装指定版本的ruby
yum install -y rh-ruby24
#使升级后的配置生效
scl enable rh-ruby24 bash
# 查看ruby版本
ruby -v
#ruby 2.4.6p354 (2019-04-01 revision 67394) [x86_64-linux]

# 这里有个坑,一旦重启reboot now后,版本又变回去了,解决如下:
vim /etc/profile.d/rh-ruby24.sh
#内容如下:
#!/bin/bash
source /opt/rh/rh-ruby24/enable
export X_SCLS="`scl enable rh-ruby24 'echo $X_SCLS'`"
export PATH=$PATH:/opt/rh/rh-ruby24/root/usr/local/bin

# 使升级后的配置生效,加载环境变量
scl enable rh-ruby24 bash
# 查看ruby版本
ruby -v
#ruby 2.4.6p354 (2019-04-01 revision 67394) [x86_64-linux]

3.2.安装ruby脚本运行所需的依赖包gem(redis版本<5.xxx)

下载网站:https://bundler.rubygems.org/gems/redis/versions/4.2.5

#将下载后的redis-4.2.5.gem上传到/usr/local/bin/cluster-config下
redis-4.2.5.gem
#安装依赖包
gem install redis-4.2.5.gem
#将redis源码包下的redis-trib.rb复制到redis-cluster目录下
cp /opt/redis/redis-6.0.6/src/redis-trib.rb /usr/local/bin/cluster-config/

3.3.设置6个实例配置文件并脚本启动

cd /usr/local/bin/cluster-config
mkdir 6379 6380 6381 6382 6383 6384
cp /opt/redis/redis-6.0.6/redis.conf/redis.conf 6379/redis.conf
cp /opt/redis/redis-6.0.6/redis.conf/redis.conf 6380/redis.conf
cp /opt/redis/redis-6.0.6/redis.conf/redis.conf 6381/redis.conf
cp /opt/redis/redis-6.0.6/redis.conf/redis.conf 6382/redis.conf
cp /opt/redis/redis-6.0.6/redis.conf/redis.conf 6383/redis.conf
cp /opt/redis/redis-6.0.6/redis.conf/redis.conf 6384/redis.conf

#拷贝redis-server到6379 6380 6381 6382 6383 6384文件夹之中
cp ../redis-server 6379 
cp ../redis-server 6380 
cp ../redis-server 6381 
cp ../redis-server 6382 
cp ../redis-server 6383 
cp ../redis-server 6384 

每一个redis.conf都修改如下内容(最低修改):

port 6379
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

编写脚本,启动6个redis实例

cd /usr/local/bin/cluster-config
vim start.sh
#内容如下:
cd 6379
./redis-server redis.conf
cd ..
cd 6380
./redis-server redis.conf
cd ..
cd 6381
./redis-server redis.conf
cd ..
cd 6382
./redis-server redis.conf
cd ..
cd 6383
./redis-server redis.conf
cd ..
cd 6384
./redis-server redis.conf
cd ..

#设置执行权限
chmod ugo+x start.sh
#运行start.sh脚本
./start.sh

如下图所示

3.4.创建集群

至此6个redis节点启动成功,接下来正式开启搭建集群,以上都是准备条件

(redis版本<5.xxx)

./redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384

(redis版本>=5.xxx)

redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 --cluster-replicas 1

使用create命令 --replicas 1 参数表示为每个主节点创建一个从节点,其他参数是实例的地址集合。

[root cluster-config]# redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:6383 to 127.0.0.1:6379
Adding replica 127.0.0.1:6384 to 127.0.0.1:6380
Adding replica 127.0.0.1:6382 to 127.0.0.1:6381
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 6c731751599000bfb2af12ff62354fe82d1d7b84 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
M: eee9755723c541ff5d88945febe5a4fd2b2a1001 127.0.0.1:6380
   slots:[5461-10922] (5462 slots) master
M: 4c23d8f1139c04bdd341b34ac84d880827550241 127.0.0.1:6381
   slots:[10923-16383] (5461 slots) master
S: 7e87d571592088aa7dcd06182e00ce21b3468e32 127.0.0.1:6382
   replicates eee9755723c541ff5d88945febe5a4fd2b2a1001
S: e38fb18fc4c493f23ce7c9743857f905e84081f7 127.0.0.1:6383
   replicates 4c23d8f1139c04bdd341b34ac84d880827550241
S: 08a1d2f9868c6dda312e60c23299667d716acc1e 127.0.0.1:6384
   replicates 6c731751599000bfb2af12ff62354fe82d1d7b84
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.
>>> Performing Cluster Check (using node 127.0.0.1:6379)
M: 6c731751599000bfb2af12ff62354fe82d1d7b84 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 4c23d8f1139c04bdd341b34ac84d880827550241 127.0.0.1:6381
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 7e87d571592088aa7dcd06182e00ce21b3468e32 127.0.0.1:6382
   slots: (0 slots) slave
   replicates eee9755723c541ff5d88945febe5a4fd2b2a1001
S: e38fb18fc4c493f23ce7c9743857f905e84081f7 127.0.0.1:6383
   slots: (0 slots) slave
   replicates 4c23d8f1139c04bdd341b34ac84d880827550241
S: 08a1d2f9868c6dda312e60c23299667d716acc1e 127.0.0.1:6384
   slots: (0 slots) slave
   replicates 6c731751599000bfb2af12ff62354fe82d1d7b84
M: eee9755723c541ff5d88945febe5a4fd2b2a1001 127.0.0.1:6380
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

两条redis集群基本命令

# 查看当前集群信息
cluster info
# 查看集群里有多少个节点
cluster nodes

3.5.集群扩容

新建6385、6386节点,加入集群,指定6385为主,6386为从,并为6385分配384个槽位

1.准备工作

# 切换目录
cd /usr/local/bin/cluster-config
mkdir 6385 6386
# 分别生成配置文件,并修改端口号
cp 6379/redis.conf 6385/
cp 6379/redis.conf 6386/

cp ../redis-server 6385/
cp ../redis-server 6386/
# 启动服务
6385/redis-server 6385/redis.conf
6386/redis-server 6386/redis.conf

查看redis cluster集群的命名大全

# 切换目录
cd /usr/local/bin/cluster-config
redis-cli --cluster help

2.将新节点中的master节点6385加入已有集群

# 切换目录
cd /usr/local/bin/cluster-config
redis-cli -h 127.0.0.1 -p 6379 --cluster add-node 127.0.0.1:6385 127.0.0.1:6379
# 查询集群
redis-cli -h 127.0.0.1 -p 6379 cluster nodes

3.将新节点中的slave节点6386加入集群(–cluster-slave),指定master节点集群Id(–cluster-master-id)

# 切换目录
cd /usr/local/bin/cluster-config
redis-cli -h 127.0.0.1 -p 6379 --cluster add-node 127.0.0.1:6386 127.0.0.1:6379 --cluster-slave --cluster-master-id a4e969f80ca9634e83cc0cc6e8ea1a4689dcba5b
# 其中a4e969f80ca9634e83cc0cc6e8ea1a4689dcba5b指的是6385的id

4.给新master节点(6385)分配槽位

redis-cli -h 127.0.0.1 -p 6379 --cluster reshard 127.0.0.1:6385

分配多少槽位

How many slots do you want to move (from 1 to 16384)? 384

分配给哪个节点(6385节点集群Id)

What is the receiving node ID? a4e969f80ca9634e83cc0cc6e8ea1a4689dcba5b

从哪个节点分割槽位给新节点,可以多个,输入done表示结束(6379节点集群Id:63249b39e5fade6fa6f17b6158ccbc1f9f0996ea)

Source node #1: 63249b39e5fade6fa6f17b6158ccbc1f9f0996ea
Source node #2: done

接着输入yes确认分配,查看集群信息,分配完成

Do you want to proceed with the proposed reshard plan (yes/no)? yes

3.6.集群缩容

1.归还6379节点槽位

# 切换目录
cd /usr/local/bin/cluster-config
redis-cli -h 127.0.0.1 -p 6379 --cluster reshard --cluster-from a4e969f80ca9634e83cc0cc6e8ea1a4689dcba5b --cluster-to 63249b39e5fade6fa6f17b6158ccbc1f9f0996ea --cluster-slots 384 127.0.0.1:6385

输入yes确认

Do you want to proceed with the proposed reshard plan (yes/no)? yes

2.移除6385、6386节点

# 切换目录
cd /usr/local/bin/cluster-config
redis-cli --cluster del-node 127.0.0.1:6385 1de56b252c703cd8fec6356d30088f188a3537b7
redis-cli --cluster del-node 127.0.0.1:6386 a4e969f80ca9634e83cc0cc6e8ea1a4689dcba5b

3.关闭6385、6386节点

# 切换目录
cd /usr/local/bin/cluster-config
redis-cli -h 127.0.0.1 -p 6385 shutdown
redis-cli -h 127.0.0.1 -p 6386 shutdown

4.springboot2.x的集成和工具类封装

4.1.引入pom.xml文件maven依赖包

基础包

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 要用redis连接池 必须有pool依赖-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

4.2.配置文件application.properties

#redis
#集群设置
#spring.redis.host=127.0.0.1
#spring.redis.port=6379
spring.redis.cluster.max-redirects=6
spring.redis.cluster.nodes=127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
#默认0号数据库
spring.redis.database=0
#连接超时时间(毫秒)默认是2000ms
spring.redis.timeout=2000ms
# lettuce 连接池配置
#连接池最大连接数(使用负值表示没有限制) 默认为8
spring.redis.lettuce.pool.max-active=8
# 连接池中的最大空闲连接 默认为8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认为 0
spring.redis.lettuce.pool.min-idle=0
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认为-1
spring.redis.lettuce.pool.max-wait=-1ms

4.3.重写redisTemplate

增加一个redisConfig配置类

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 使用Jackson2JsonRedisSerialize 替换默认的jdkSerializeable序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

4.4.封装Redis工具类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
public class RedisCacheManager {

    @Autowired
    @Qualifier(value = "redisTemplate")
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 指定缓存失效时间
     *
     * @param key
     *            键
     * @param time
     *            时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     *
     * @param key
     *            键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @param key
     *            键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key
     *            可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

    // ============================String=============================
    /**
     * 普通缓存获取
     *
     * @param key
     *            键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     *
     * @param key
     *            键
     * @param value
     *            值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key
     *            键
     * @param value
     *            值
     * @param time
     *            时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 递增
     *
     * @param key
     *            键
     * @param delta
     *            要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @param key
     *            键
     * @param delta
     *            要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    // ================================Map=================================
    /**
     * HashGet
     *
     * @param key
     *            键 不能为null
     * @param item
     *            项 不能为null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取hashKey对应的所有键值
     *
     * @param key
     *            键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     *
     * @param key
     *            键
     * @param map
     *            对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashSet 并设置时间
     *
     * @param key
     *            键
     * @param map
     *            对应多个键值
     * @param time
     *            时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key
     *            键
     * @param item
     *            项
     * @param value
     *            值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key
     *            键
     * @param item
     *            项
     * @param value
     *            值
     * @param time
     *            时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除hash表中的值
     *
     * @param key
     *            键 不能为null
     * @param item
     *            项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key
     *            键 不能为null
     * @param item
     *            项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key
     *            键
     * @param item
     *            项
     * @param by
     *            要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     *
     * @param key
     *            键
     * @param item
     *            项
     * @param by
     *            要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    // ============================set=============================
    /**
     * 根据key获取Set中的所有值
     *
     * @param key
     *            键
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key
     *            键
     * @param value
     *            值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     *
     * @param key
     *            键
     * @param values
     *            值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 将set数据放入缓存
     *
     * @param key
     *            键
     * @param time
     *            时间(秒)
     * @param values
     *            值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0)
                expire(key, time);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @param key
     *            键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值为value的
     *
     * @param key
     *            键
     * @param values
     *            值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    // ===============================list=================================

    /**
     * 获取list缓存的内容
     *
     * @param key
     *            键
     * @param start
     *            开始
     * @param end
     *            结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @param key
     *            键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 通过索引 获取list中的值
     *
     * @param key
     *            键
     * @param index
     *            索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key
     *            键
     * @param value
     *            值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key
     *            键
     * @param value
     *            值
     * @param time
     *            时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key
     *            键
     * @param value
     *            值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key
     *            键
     * @param value
     *            值
     * @param time
     *            时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @param key
     *            键
     * @param index
     *            索引
     * @param value
     *            值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N个值为value
     *
     * @param key
     *            键
     * @param count
     *            移除多少个
     * @param value
     *            值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

4.5.写个测试类测试

@SpringBootTest
class ApplicationTests {

    @Autowired
    RedisCacheManager redisCacheManager;

    @Test
    void contextLoads() {
        redisCacheManager.set("hello","world");
        System.out.println(redisCacheManager.get("hello"));
    }

}

能看完的都是大神,请大神给个关注,欢迎大家留言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彼岸花@开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值