redis应用

## Redis集群搭建

### 一、主从模式

#### 1. 什么是主从复制

主机数据更新后根据配置和策略,自动同步到备机的master/slave机制,Master以写为主,Slave以读为主。

这样就可以起到读写分离、性能扩展,容灾快速恢复的目的。

#### 2. 配置主从复制

##### 2.1 准备工作

~~~bash
mkdir /myredis
~~~

进入myredis,复制redis.conf配置文件到myredis文件夹中

~~~bash
cp /opt/redis-6.2.5/redis.conf /myredis/redis.conf
~~~

打开redis.conf 

找到appendonly配置为no

~~~sh
appendonly no
~~~

密码设置为:

~~~
requirepass 8a6b67qa@WSDE#
~~~

##### 2.2 配置一主两从

创建一个配置文件

~~~bash
touch redis6379.conf
~~~

在三个配置文件中写入内容

~~~sh
include /myredis/redis.conf       #引入配置文件的公共部分,其他的单独进行配置
pidfile /var/run/redis6379.pid    #写入pid的文件位置
port 6379                         #设置端口为6379
dbfilename dump6379.rdb           #设置redis数据库文件名字
masterauth "8a6b67qa@WSDE#"       #连接主机的密码
~~~

##### 2.3 复制其他两个从机的配置

~~~bash
cp redis6379.conf redis6380.conf
cp redis6379.conf redis6381.conf
~~~

打开文件进行第3步的操作修改

##### 2.4 启动三台服务器

~~~bash
redis-server redis6379.conf
redis-server redis6380.conf
redis-server redis6381.conf
~~~

查看redis启动进程

~~~
ps -ef | grep redis
~~~

分别连接三台服务器,查看三台主机的运行情况

info replication 打印主从复制的相关信息

##### 2.5 配置从机

配置从机成为指定实例主服务器的从服务器,主机上不要设置

在6380和6381两台从机上执行:

~~~
slaveof 127.0.0.1 6379
~~~

如果一台从机挂掉了,那么启动后它就是一台独立的服务器,需要重新配置为从机,然后就可以正常的共享数据了

如果主机挂掉了,从机还是从机并没有改变主从关系,当主机重启后,不需要重新配置



#### 3. 主从复制的实现原理

1、 当从机连接上主机后,从服务器向主服务器发送请求,进行数据同步消息

2、 主服务接收到从服务器发送过来同步消息,把主服务器数据先进行持久化,放入到rdb文件中,把rdb文件发送到从服务器,从服务器拿到rdb文件,进行读取

3、每次主服务器进行写操作之后,主动和从服务器进行数据同步



#### 4. 实战中的三种配置模式

##### 4.1 一主多仆

刚才配置的主从复制就是一主多仆模式,主机shutdown后,从机还是原地待命,并不会上位成为主机。

##### 4.2 薪火相传

就是把一台从机设置为另一台从机的主机,形成一个链条 。

缺点:链条断了就不能再继续进行

在6381下进行如下操作,就可以实现

~~~bash
slaveof 127.0.0.1 6380
~~~

上一个Slave可以是下一个Slave的Master,Slave同样可以接收其他Slaves的连接和同步请求,那么该Slave做为链条中的下一个Master,可以有效减轻Master的复制从机数据的压力,去中心化的思想,降低风险。

风险是:一旦某个Slave宕机,后面的Slave都没法备份。主机一旦挂了,从机依然还是从机,无法写数据了。

##### 4.3 反客为主

当一个主机master宕机后,后面的slave从机立即升级为master,其后面的slave不用做任何修改

使用命令

~~~bash
slaveof no one #将从机变成主机
~~~

停掉6379,设置6380

缺点:需要手动的进行设置



### 二、哨兵模式

反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库

![无标题2](Redis-3.assets/无标题2.png)

#### 1. 先配置成一主多仆模式

把刚才设置成的薪火相传,重新设置主机

~~~shell
slaveof 127.0.0.1 6379
~~~

#### 2. 准备工作

在myredis下新建sentinel.conf文件,名字不能写错

#### 3. 配置哨兵

~~~sh
sentinel monitor mymaster 127.0.0.1 6379 1
sentinel auth-pass mymaster "8a%&^AeE6b67qa@WSDE#"
~~~

其中mymaster为监控对象起的服务器名称,1为至少有多少个哨兵同意迁移的数量。

#### 4. 启动哨兵

~~~bash
 redis-sentinel /myredis/sentinel.conf
~~~

当主机挂掉,从机选举中产生新的主机



哪个从机会被选为主机呢?根据优先级:slave-priority,在这种模式下,原来的主机重启后,会变成从机。

优先级在redis.conf中默认:slave-priority 100 ,值越小优先级越高。

注意:redis新版本中的名称叫:replica-priority。

大概10-20秒钟左右,可以看到哨兵窗口日志的输出,切换了新的主机

选举条件依次为:

- 选择优先级靠前的

- 选择偏移量最大的

  偏移量指的是获得原主机数据最全的

- 选择runid最小的从服务器

  每个redis实例启动后,都会随机生成一个40位的runid,运行id由40位字符组成,是一个随机的十六进制字符,例如:

  7cfbf53e4901277d7247db9fac7945af44dcc666

  运行id在每台服务器启动时自动生成的,master在首次连接slave时,会将自己的运行ID发送给slave,slave保存此ID,通过info Server命令,可以查看节点的runid

  ~~~shell
  redis-cli -p 6379 info server | grep run
  ~~~


#### 5. 复制延时

由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。



### 三、阿里云搭建Redis哨兵模式

> 一主两从三哨兵集群配置方案:

当master节点宕机时,通过哨兵(sentinel)重新推选出新的master节点,保证集群的可用性。

哨兵的主要功能:

1.集群监控:负责监控 Redis master 和 slave 进程是否正常工作。

2.消息通知:如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。

3.故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。

4.配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。

![2021062109150312](Redis-3.assets/2021062109150312.png)





#### 1. 下载安装Redis到服务器

此处步骤略

#### 2. 配置Redis步骤

##### 2.1 在根目录下创建文件夹

~~~bash
mkdir redis
cd redis
mkdir data   #准备存放数据的文件夹
mkdir log    #存放日志的文件夹
~~~

##### 2.2 拷贝文件到根目录

~~~bash
cp /opt/redis-6.2.5/redis.conf /redis
~~~

##### 2.3 修改配置文件(说明)

~~~bash
vim redis.conf
~~~

~~~shell
#注释掉bind,允许远程访问
#bind 127.0.0.1 -::1

#表示Redis可以接受任意ip的连接
bind 0.0.0.0

#打开后台启动
daemonize yes

#设置权限密码
requirepass 8a%&^AeE6b67qa@WSDE#

#设置从节点连接主节点密码
masterauth 8a%&^AeE6b67qa@WSDE#

#关闭保护模式
protected-mode no

#注释端口号
#port 6379

#注释pid文件
#pidfile /var/run/redis_6379.pid

#注释日志文件
#logfile ""

#开启默认的rdb文件
save 3600 1
save 300 100
save 60 10000

#每一个端口都会有对应的rdb文件,这个需要注释
#dbfilename dump.rdb

#存放在根目录的data文件目录下
dir /redis/data

#从服务器默认只读
replica-read-only yes
~~~

##### 2.4 创建三个配置文件

在redis的跟目录下,创建三个配置文件,6379做为主机,6380与6381做为从机

~~~properties
touch redis6379.conf
touch redis6380.conf
touch redis6381.conf
~~~

在6379配置文件中写入内容:

~~~properties
#引入公共的redis.conf文件配置
include /redis/redis.conf
# 进程编号记录文件
pidfile /var/run/redis-6379.pid
# 进程端口号
port 6379
# 日志记录文件
logfile "/redis/log/redis-6379.log"
# 数据记录文件名称
dbfilename dump-6379.rdb
# 追加文件名称
appendfilename "appendonly-6379.aof"
~~~

~~~sh
include /redis/redis.conf
pidfile /var/run/redis-6379.pid
port 6379
logfile "/redis/log/redis-6379.log"
dbfilename dump-6379.rdb
appendfilename "appendonly-6379.aof"
~~~



在6380配置文件中写入内容

~~~properties
#引入公共的redis.conf文件配置
include /redis/redis.conf
# 进程编号记录文件
pidfile "/var/run/redis-6380.pid"
# 进程端口号
port 6380
# 日志记录文件
logfile "/redis/log/redis-6380.log"
# 数据记录文件
dbfilename "dump-6380.rdb"
# 追加文件名称
appendfilename "appendonly-6380.aof"
# 下面的配置无需在6379里配置
# # 备份服务器从属于6379推荐配置局域网ip
replicaof 116.62.32.11 6379
~~~

~~~sh
include /redis/redis.conf
pidfile "/var/run/redis-6380.pid"
port 6380
logfile "/redis/log/redis-6380.log"
dbfilename "dump-6380.rdb"
appendfilename "appendonly-6380.aof"
replicaof 116.62.32.11 6379
~~~



在6381配置文件中写入内容

~~~properties
#引入公共的redis.conf文件配置
include /redis/redis.conf
# 进程编号记录文件
pidfile "/var/run/redis-6381.pid"
# 进程端口号
port 6381
# 日志记录文件
logfile "/redis/log/redis-6381.log"
# 数据记录文件
dbfilename "dump-6381.rdb"
# 追加文件名称
appendfilename "appendonly-6381.aof"
# 下面的配置无需在6379里配置
# # 备份服务器从属于6379推荐配置局域网ip
replicaof 116.62.32.11 6379
~~~

~~~sh
include /redis/redis.conf
pidfile "/var/run/redis-6381.pid"
port 6381
logfile "/redis/log/redis-6381.log"
dbfilename "dump-6381.rdb"
appendfilename "appendonly-6381.aof"
replicaof 116.62.32.11 6379
~~~



##### 2.5 启动服务

启动三个redis服务

~~~properties
redis-server redis6379.conf
redis-server redis6380.conf
redis-server redis6381.conf
~~~

查看redis启动进程

~~~shell
ps -ef | grep redis
~~~

通过redis-cli指令分别连接三台服务器,查看三台主机的运行情况

~~~shell
info replication
~~~

打印主从复制的相关信息

##### 2.6 配置哨兵模式

在根目录的redis中,创建sentinel.conf文件

~~~shell
touch sentinel.conf
~~~

配置内容如下

~~~properties
daemonize yes
sentinel monitor mymaster 116.62.32.11 6379 2
sentinel auth-pass mymaster 123456
~~~

> 哨兵监控主从  这个2 是这边开启三台服务器 如果要选举服务器就需要大于百分之50才能选举成功  3台服务器如果要选一台就需要2台的投票数



~~~properties
#是否要用守护线程的方式启动,采用yes时,redis会在后台运行
daemonize yes
# 表示接收所有ip的请求
bind 0.0.0.0
#告诉redis监控,ip为39.105.163.81,端口号为6379,名为mymaster的主节点,quorum设为2。
#quorum的含义:
#确认主节点不可达需要经过多少哨兵同意
#(从而将该主机标记为失效,并触发故障转移机制)
#quorum只用于监测失效的主节点。当某个哨兵被选为执行故障转移的首领后,才能由其进行具体的转移操作。
sentinel monitor mymaster 39.105.163.81 6379 2
# 密码
sentinel auth-pass mymaster 20020929_wskE@
# 主服务器超时时间,秒为单位
sentinel down-after-milliseconds mymaster 30000
# 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长,但越大就意味着越多的从服务器因为复制而不可用。可以通过将这个值设为1来保证每次只有一个从服务器处于不能处理命令请求的状态。
sentinel parallel-syncs mymaster 1
# 选举新主服务器的最小超时时间
sentinel failover-timeout mymaster 180000
#sentinel的节点ip地址
sentinel announce-ip 39.105.163.81
#sentinel的节点端口号
sentinel announce-port 26379
~~~

复制下面的内容写入sentinel.conf即可

~~~
daemonize yes
bind 0.0.0.0
sentinel monitor mymaster 39.105.163.81 6379 2
sentinel auth-pass mymaster 20020929_wskE@
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel announce-ip 39.105.163.81
sentinel announce-port 26379
~~~



再创建三个配置文件

~~~shell
touch sentinel26379.conf
touch sentinel26380.conf
touch sentinel26381.conf
~~~

编辑sentinel26379.conf内容

~~~properties
#引用公共配置
include /redis/sentinel.conf
##进程端口号
port 26379
##进程编号记录文件
pidfile "/var/run/sentinel-26379.pid"
##日志记录文件(为了方便查看日志,先注释掉,搭建好环境后再打开
logfile "/redis/log/sentinel-26379.log"
~~~

~~~sh
include /redis/sentinel.conf
port 26379
pidfile "/var/run/sentinel-26379.pid"
logfile "/redis/log/sentinel-26379.log"
~~~



编辑sentinel26380.conf内容

~~~properties
#引用公共配置
include /redis/sentinel.conf
#进程端口号
port 26380
#进程编号记录文件
pidfile "/var/run/sentinel-26380.pid"
#日志记录文件(为了方便查看日志,先注释掉,搭建好环境后再打开
logfile "/redis/log/sentinel-26380.log"
~~~

~~~sh
include /redis/sentinel.conf
port 26380
pidfile "/var/run/sentinel-26380.pid"
logfile "/redis/log/sentinel-26380.log"
~~~



编辑sentinel26381.conf内容

~~~properties
#引用公共配置
include /redis/sentinel.conf
#进程端口号
port 26381
#进程编号记录文件
pidfile "/var/run/sentinel-26381.pid"
#日志记录文件(为了方便查看日志,先注释掉,搭建好环境后再打开
logfile "/redis/log/sentinel-26381.log"
~~~

~~~sh
include /redis/sentinel.conf
port 26381
pidfile "/var/run/sentinel-26381.pid"
logfile "/redis/log/sentinel-26381.log"
~~~



启动三个哨兵

~~~properties
redis-sentinel sentinel26379.conf
redis-sentinel sentinel26380.conf
redis-sentinel sentinel26381.conf
~~~

然后再开启三个窗口查看哨兵日志

~~~shell
tail -f  /redis/log/sentinel-26379.log
tail -f  /redis/log/sentinel-26380.log
tail -f  /redis/log/sentinel-26381.log
~~~

测试:现在把主机6379杀死等待30秒,看日志输出

##### 2.7 开启端口

要在阿里云控制台的安全组中开放端口,同时在linux服务器的防火墙中添加开放的端口

防火墙命令

~~~sh
#查看firewall服务状态
systemctl status firewalld

#开启防火墙服务
systemctl start firewalld 

#重启
systemctl restart firewalld 

#关闭
systemctl  stop firewalld 


#开启端口
firewall-cmd --zone=public --add-port=6379/tcp --permanent 
#含义:
--zone   #设置作用域为全局生效
--add-port=8080/tcp #添加端口
--permanent   #永久生效

# 配置立即生效
firewall-cmd --reload  

#查看已经加入防火墙的端口号
firewall-cmd --zone=public --list-ports 

#查看防火墙规则
firewall-cmd --list-all

#检查端口被哪个进程占用
netstat -lnpt|grep 8080

~~~

启动顺序为:先主,后从,再哨兵。启动后先检测哨兵的日志

A:   B   C

B:   A   C

C:   A   B



### 四、Springboot使用redis哨兵

#### 1. 创建项目,导入maven依赖

~~~xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
~~~

#### 2. 添加yml配置信息

> lettuce连接池使用commons-pool2依赖

~~~yaml
###################以下为Redis增加的配置###########################
spring:
  data:
    redis:
      timeout: 10000
      password: 123456
      ###################以下为redis哨兵增加的配置###########################
      sentinel:
        master: mymaster
        nodes: 101.200.171.101:26379,101.200.172.102:26380,101.200.174.103:26381
      ###################以下为lettuce连接池增加的配置###########################
      lettuce:
        pool:
          max-active:  100 # 连接池最大连接数(使用负值表示没有限制)
          max-idle: 100 # 连接池中的最大空闲连接
          min-idle: 50 # 连接池中的最小空闲连接
          max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
~~~

#### 3. 配置序列化器

~~~java
package cn.hxzy.config;

/**
 * @author mengshujun
 * @create 2024/5/5 21:06
 */
import com.fasterxml.jackson.annotation.JsonAutoDetect;
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("redis")
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        //自定义Jackson序列化配置
        Jackson2JsonRedisSerializer jsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        jsonRedisSerializer.setObjectMapper(objectMapper);

        //key使用String的序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringRedisSerializer);
        //hash的key也是用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        //value的key使用jackson的序列化方式
        template.setValueSerializer(jsonRedisSerializer);
        //hash的value也是用jackson的序列化方式
        template.setHashValueSerializer(jsonRedisSerializer);
        template.afterPropertiesSet();
        return template;

    }

}
~~~



#### 4. 配置RedisSentinelConfiguration

在RedisConfig类中,添加如下方法,进行哨兵节点的注册

~~~java
@Bean
public RedisSentinelConfiguration redisSentinelConfiguration(){
    RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration()
        //主节点名称
        .master("mymaster")
        //哨兵
        .sentinel("101.200.174.107",26379)
        .sentinel("101.200.174.107",26380)
        .sentinel("101.200.174.107",26381);
    //配置的哨兵密码
    redisSentinelConfiguration.setPassword("123456");
    return redisSentinelConfiguration;
}
~~~

#### 5. 进行测试

在测试类中,写入测试代码

~~~java
@Autowired
private RedisTemplate redisTemplate;

@Autowired
private StringRedisTemplate stringRedisTemplate;

@Test
public void test01() {
    stringRedisTemplate.opsForValue().set("k2", "v2");
    String k2 = stringRedisTemplate.opsForValue().get("k2");
    System.out.println(k2);

    User u1=new User(10003,"zhangsan");
    redisTemplate.opsForValue().set("user",u1);
    Object aDo = redisTemplate.opsForValue().get("user");
    System.out.println(aDo);
}
~~~

#### 6.配置RedisUtils

企业中往往操作redis对象,总会把RedisTemplate常用的方法封装成为一个工具类,这样极大的方便操作redis,并且在工具类中统一进行了异常处理等操作。

工具:

~~~java
package cn.hxzy.util;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
public final class RedisUtils {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // =============================common============================

    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     */
    public boolean expire(String key, long time, TimeUnit timeUnit) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, timeUnit);
            }
            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((Collection<String>) CollectionUtils.arrayToList(key));
            }
        }
    }


    // ============================普通对象操作=============================

    /**
     * 普通缓存获取
     *
     * @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)
     */
    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)
     */
    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
     */
    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 对应多个键值
     */
    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, TimeUnit timeUnit) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time, timeUnit);
            }
            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, TimeUnit timeUnit) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time, timeUnit);
            }
            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)
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }


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


    // ============================set=============================

    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     */
    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, TimeUnit timeUnit, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time, timeUnit);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 获取set缓存的长度
     *
     * @param key 键
     */
    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代表所有值
     */
    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 键
     */
    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倒数第二个元素,依次类推
     */
    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 值
     */
    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  时间(秒)
     */
    public boolean lSet(String key, Object value, long time,TimeUnit timeUnit) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time,timeUnit);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List 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,TimeUnit timeUnit) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time,timeUnit);
            }
            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;
        }

    }

    // ===============================HyperLogLog=================================

    public long pfadd(String key, String value) {
        return redisTemplate.opsForHyperLogLog().add(key, value);
    }

    public long pfcount(String key) {
        return redisTemplate.opsForHyperLogLog().size(key);
    }

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

    public void pfmerge(String key1, String key2) {
        redisTemplate.opsForHyperLogLog().union(key1, key2);
    }


}

~~~














  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis是一种高性能的内存数据库,它被广泛用于各种应用场景。以下是几个常见的Redis应用场景: 1. 缓存:由于Redis的高性能和低延迟,它通常被用作数据缓存层,将频繁访问的数据存储在内存中,从而加快数据访问速度。 2. 会话存储:在分布式系统中,可以使用Redis存储用户会话信息,包括用户登录状态、权限等。这样可以轻松实现会话共享和负载均衡。 3. 发布/订阅系统:Redis支持发布/订阅模式,可以用于实时消息传递、事件通知等场景。发布者将消息发布到指定频道,订阅者可以接收到相关消息并做出相应处理。 4. 计数器和排行榜:Redis提供了原子操作的支持,可以用于实现计数器和排行榜功能。例如,可以使用Redis的INCR操作来实现网站的访问计数器,或者根据用户的积分进行排行。 5. 分布式锁:在分布式系统中,为了保证数据的一致性和并发控制,可以使用Redis的分布式锁功能。通过使用Redis的SETNX操作来获取锁,并使用EXPIRE设置锁的过期时间,可以有效地实现分布式锁。 6. 消息队列:Redis的列表结构可以用作轻量级的消息队列。生产者将消息推入列表,消费者则从列表中弹出消息进行处理。这种方式简单高效,适用于需要异步处理的场景。 这只是一部分常见的Redis应用场景,实际上,由于Redis的灵活性和高性能,它在各种场景下都有不同的应用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值