微服务开发系列 第五篇:Redis

news2025/1/11 7:07:06

总概

A、技术栈

  • 开发语言:Java 1.8
  • 数据库:MySQL、Redis、MongoDB、Elasticsearch
  • 微服务框架:Spring Cloud Alibaba
  • 微服务网关:Spring Cloud Gateway
  • 服务注册和配置中心:Nacos
  • 分布式事务:Seata
  • 链路追踪框架:Sleuth
  • 服务降级与熔断:Sentinel
  • ORM框架:MyBatis-Plus
  • 分布式任务调度平台:XXL-JOB
  • 消息中间件:RocketMQ
  • 分布式锁:Redisson
  • 权限:OAuth2
  • DevOps:Jenkins、Docker、K8S

B、本节实现目标

  • 用户数据存入Redis
  • 提供Redis存储工具类,存取各种数据结构

一、安装Redis

可参考:Ubuntu安装Redis

二、整合Redis到项目

2.1 maven加Redis依赖包

在项目[mall-pom]的pom.xml里加入Redis依赖包

<redis.version>3.0.2</redis.version>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
  <version>${redis.version}</version>
</dependency>

2.2 Nacos配置Redis地址和密码

Redis各个微服务基本上都会用到,所以和配置MySQL一样,我们将Redis的配置也放到Nacos的common.yml中。

spring:
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    password: 123abc
    jedis:
      pool:
        max-active: 500  #连接池的最大数据库连接数。设为0表示无限制
        max-idle: 20   #最大空闲数
        max-wait: -1
        min-idle: 5
    timeout: 1000

common.yml完整配置如下:

spring:
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    password: 123abc
    jedis:
      pool:
        max-active: 500  #连接池的最大数据库连接数。设为0表示无限制
        max-idle: 20   #最大空闲数
        max-wait: -1
        min-idle: 5
    timeout: 1000

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.100.51:3306/ac_db?serverTimezone=Asia/Shanghai&useUnicode=true&tinyInt1isBit=false&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
    username: ac_u
    password: ac_PWD_123

    #hikari数据库连接池
    hikari:
      pool-name: YH_HikariCP
      minimum-idle: 10 #最小空闲连接数量
      idle-timeout: 600000 #空闲连接存活最大时间,默认600000(10分钟)
      maximum-pool-size: 100 #连接池最大连接数,默认是10
      auto-commit: true  #此属性控制从池返回的连接的默认自动提交行为,默认值:true
      max-lifetime: 1800000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
      connection-timeout: 30000 #数据库连接超时时间,默认30秒,即30000
      connection-test-query: SELECT 1

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.3 测试Redis

在服务[mall-member]中新建一个测试类RedisTestController

package com.ac.member.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@Api(tags = "Redis测试")
@RestController
@RequestMapping("redis")
public class RedisTestController {

    @Resource
    private RedisTemplate redisTemplate;

    @ApiOperation(value = "存-取-字符串")
    @GetMapping("testString")
    public String testString(@RequestParam String value) {
        String key = "memberName";
        redisTemplate.opsForValue().set(key, value);
        Object result = redisTemplate.opsForValue().get(key);
        if (result != null) {
            return result.toString();
        }
        return "";
    }
}

测试结果

测试结果

2.4 SpringBoot使用RedisTemplate乱码问题

2.4.1 现象

在使用RedisTemplate进行set、put操作时,会有乱码产生。

乱码

2.4.2 原因分析

RedisTemplate序列化默认使用的jdkSerializeable,存储二进制字节码,导致key会出现乱码。

2.4.3 解决方案

改变序列化方式

package com.ac.common.config.redis;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

/**
 * @description Redis相关配置
 */
@Configuration
public class RedisRepositoryConfig {

    /**
     * 日期时间格式
     */
    private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    /**
     * 日期格式
     */
    private static final String DATE_FORMAT = "yyyy-MM-dd";
    /**
     * 时间格式
     */
    private static final String TIME_FORMAT = "HH:mm:ss";

    @Bean
    public RedisSerializer<String> redisKeySerializer() {
        return RedisSerializer.string();
    }

    @Bean
    public RedisSerializer<Object> redisValueSerializer() {
        return RedisSerializer.json();
    }

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

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 此项必须配置,否则会报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);


        //LocalDateTime系列序列化和反序列化模块,继承自jsr310,我们在这里修改了日期格式
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(
                DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
        javaTimeModule.addSerializer(LocalDate.class,
                new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
        javaTimeModule.addSerializer(LocalTime.class,
                new LocalTimeSerializer(DateTimeFormatter.ofPattern(TIME_FORMAT)));

        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(
                DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
        javaTimeModule.addDeserializer(LocalDate.class,
                new LocalDateDeserializer(DateTimeFormatter.ofPattern(DATE_FORMAT)));
        javaTimeModule.addDeserializer(LocalTime.class,
                new LocalTimeDeserializer(DateTimeFormatter.ofPattern(TIME_FORMAT)));

        objectMapper.registerModule(javaTimeModule);

        GenericToStringSerializer genericToStringSerializer = new GenericToStringSerializer(Object.class);
        //字符串序列化器
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //Jackson序列化器
        Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(genericToStringSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.setEnableDefaultSerializer(false);
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

}

乱码解决

三、用Redis缓存用户数据

3.1 缓存用户类

package com.ac.member.rds;

import com.ac.common.util.redis.RdsComponent;
import com.ac.member.entity.Member;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class MemberRds {

    @Resource
    private RdsComponent rdsComponent;

    /**
     * 用前缀,组成目录的结构
     */
    private static final String KEY_PREFIX = "member:";

    public Boolean save(Member obj) {
        return rdsComponent.hmSetObj(populateKey(obj.getId()), obj);
    }

    public Member get(Long id) {
        return rdsComponent.hmGetObj(populateKey(id), Member.class);
    }

    private String populateKey(Long id) {
        return KEY_PREFIX + id;
    }
}

3.2 service存用户到Redis

@Slf4j
@Service
public class MemberServiceImpl implements MemberService {

    @Resource
    private MemberDao memberDaoImpl;

    @Resource
    private MemberRds memberRds;

    @Override
    public Member findById(Long id) {
        return Optional.ofNullable(memberDaoImpl.getById(id)).orElseThrow(() -> new RuntimeException("数据不存在"));
    }

    @Override
    public MemberDTO findMember(Long id) {
        Member entity = memberRds.get(id);
        if (entity == null) {
            entity = findById(id);
            memberRds.save(entity);
            log.info("从数据库查数据,id={}", id);
        }
        return MemberConvert.instance.entityToDto(entity);
    }

    @Override
    public Boolean addMember(MemberEditVO editVO) {
        Member entity = MemberConvert.instance.editVoToEntity(editVO);
        boolean result = memberDaoImpl.save(entity);
        if (result) {
            memberRds.save(entity);
        }
        return result;
    }
}

3.3 Redis数据库存储用户数据情况

Redis用户数据

四、Redis存储工具类

4.1 说明

com.ac.common.util.redis.RdsComponent 该工具类提供了Redis中6大数据类型的存储方法

redis数据类型

4.2 RdsComponent工具类代码

package com.ac.common.util.redis;

import com.ac.common.util.redis.tool.*;
import org.springframework.data.geo.*;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @description Redis工具类
 */
@Component
public class RdsComponent {

    @Resource
    private RdsCommonTool rdsCommonTool;

    @Resource
    private RdsStringTool rdsStringTool;

    @Resource
    private RdsHashTool rdsHashTool;

    @Resource
    private RdsListTool rdsListTool;

    @Resource
    private RdsSetTool rdsSetTool;

    @Resource
    private RdsZSetTool rdsZSetTool;

    @Resource
    private RdsGeoTool rdsGeoTool;

    //============================第1部分:common start=============================

    /**
     * 是否有key
     *
     * @param key
     * @return
     */
    public boolean hasKey(String key) {
        return rdsCommonTool.hasKey(key);
    }

    /**
     * 返回key集合
     *
     * @param key 键
     * @return
     */
    public Set<String> keys(String key) {
        return rdsCommonTool.keys(key);
    }

    /**
     * 设置key的过期时间(默认单位:秒)
     *
     * @param key
     * @param time
     * @return
     */
    public boolean expire(String key, long time) {
        return rdsCommonTool.expire(key, time);
    }

    /**
     * 设置key的过期时间
     *
     * @param key
     * @param time
     * @param timeUnit
     * @return
     */
    public boolean expire(String key, long time, TimeUnit timeUnit) {
        return rdsCommonTool.expire(key, time, timeUnit);
    }

    /**
     * 获取key的过期时间(默认单位:秒)
     *
     * @param key
     * @return
     */
    public long getExpire(String key) {
        return rdsCommonTool.getExpire(key);
    }

    /**
     * 获取key的过期时间
     *
     * @param key
     * @param timeUnit
     * @return
     */
    public long getExpire(String key, TimeUnit timeUnit) {
        return rdsCommonTool.getExpire(key, timeUnit);
    }

    /**
     * 删除key
     *
     * @param key
     * @return
     */
    public Boolean del(String... key) {
        return rdsCommonTool.del(key);
    }

    /**
     * 批量删除key
     *
     * @param keys
     * @return
     */
    public Long del(Collection<String> keys) {
        return rdsCommonTool.del(keys);
    }

    //============================第1部分:common end=============================

    //============================第2部分:String start=============================

    /**
     * String-获取String
     *
     * @param key
     * @return
     */
    public String getStr(String key) {
        return rdsStringTool.getStr(key);
    }

    /**
     * String-获取基本数据类型对象
     *
     * @param key
     * @return
     */
    public Object get(String key) {
        return rdsStringTool.get(key);
    }

    /**
     * String-设置基本数据类型对象(不过期)
     *
     * @param key
     * @param value
     * @return
     */
    public boolean set(String key, Object value) {
        return rdsStringTool.set(key, value);
    }

    /**
     * String-设置基本数据类型对象(过期时间,默认单位:秒)
     *
     * @param key
     * @param value
     * @return
     */
    public boolean set(String key, Object value, long time) {
        return rdsStringTool.set(key, value, time);
    }

    /**
     * String-设置基本数据类型对象(过期时间,过期单位)
     *
     * @param key
     * @param value
     * @return
     */
    public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
        return rdsStringTool.set(key, value, time, timeUnit);
    }

    /**
     * String-设置基本数据类型对象-不过期(只有在key不存在时设置key的值)
     *
     * @param key
     * @param value
     * @return
     */
    public boolean setIfAbsent(String key, Object value) {
        return rdsStringTool.setIfAbsent(key, value);
    }

    /**
     * String-设置基本数据类型对象(只有在key不存在时设置key的值)
     *
     * @param key
     * @param value
     * @return
     */
    public boolean setIfAbsent(String key, Object value, long time) {
        return rdsStringTool.setIfAbsent(key, value, time);
    }

    /**
     * String-设置基本数据类型对象(只有在key不存在时设置key的值)
     *
     * @param key
     * @param value
     * @return
     */
    public boolean setIfAbsent(String key, Object value, long time, TimeUnit timeUnit) {
        return rdsStringTool.setIfAbsent(key, value, time, timeUnit);
    }

    /**
     * String-递增(默认按1递增)
     *
     * @param key
     * @return
     */
    public long incr(String key) {
        return rdsStringTool.incr(key);
    }

    /**
     * String-递增(递增幅度)
     *
     * @param key
     * @param delta
     * @return
     */
    public long incr(String key, long delta) {
        return rdsStringTool.incr(key, delta);
    }

    /**
     * String-递减(默认按1递减)
     *
     * @param key
     * @return
     */
    public long decr(String key) {
        return rdsStringTool.decr(key);
    }

    /**
     * String-递减(递减幅度)
     *
     * @param key
     * @param delta
     * @return
     */
    public long decr(String key, long delta) {
        return rdsStringTool.decr(key, delta);
    }

    //============================第2部分:String end=============================

    //================================第3部分:Hash start=================================

    /**
     * Hash-取对象字段
     *
     * @param key
     * @param item
     * @return
     */
    public Object hGet(String key, String item) {
        return rdsHashTool.hGet(key, item);
    }

    /**
     * Hash-取对象
     *
     * @param key
     * @param target
     * @param <T>
     * @return
     */
    public <T> T hmGetObj(String key, Class<T> target) {
        return rdsHashTool.hmGetObj(key, target);
    }

    /**
     * Hash-存对象
     *
     * @param key
     * @param object
     * @return
     */
    public boolean hmSetObj(String key, Object object) {
        return rdsHashTool.hmSetObj(key, object);
    }

    /**
     * Hash-存对象(设置过期时间,单位默认秒)
     *
     * @param key
     * @param object
     * @param time
     * @return
     */
    public boolean hmSetObj(String key, Object object, long time) {
        return rdsHashTool.hmSetObj(key, object, time);
    }

    /**
     * Hash-存对象(设置过期时间,单位)
     *
     * @param key
     * @param object
     * @param time
     * @param timeUnit
     * @return
     */
    public boolean hmSetObj(String key, Object object, long time, TimeUnit timeUnit) {
        return rdsHashTool.hmSetObj(key, object, time, timeUnit);
    }

    /**
     * Hash-设置对象字段值
     *
     * @param key
     * @param item
     * @param value
     * @return
     */
    public boolean hSet(String key, String item, Object value) {
        return rdsHashTool.hSet(key, item, value);
    }

    /**
     * Hash-设置对象字段值(设置过期时间,单位默认秒)
     *
     * @param key
     * @param item
     * @param value
     * @param time
     * @return
     */
    public boolean hSet(String key, String item, Object value, long time) {
        return rdsHashTool.hSet(key, item, value, time);
    }

    /**
     * Hash-设置对象字段值(设置过期时间,单位)
     *
     * @param key
     * @param item
     * @param value
     * @param time
     * @param timeUnit
     * @return
     */
    public boolean hSet(String key, String item, Object value, long time, TimeUnit timeUnit) {
        return rdsHashTool.hSet(key, item, value, time, timeUnit);
    }

    /**
     * Hash-获取Map
     *
     * @param key
     * @return
     */
    public Map<Object, Object> hmGet(String key) {
        return rdsHashTool.hmGet(key);
    }

    /**
     * Hash-存Map(不过期)
     *
     * @param key
     * @param map
     * @return
     */
    public boolean hmSet(String key, Map<String, Object> map) {
        return rdsHashTool.hmSet(key, map);
    }

    /**
     * Hash-存Map-设置过期时间(单位默认秒)
     *
     * @param key
     * @param map
     * @param time
     * @return
     */
    public boolean hmSet(String key, Map<String, Object> map, long time) {
        return rdsHashTool.hmSet(key, map, time);
    }

    /**
     * Hash-存Map(设置过期时间,单位)
     *
     * @param key
     * @param map
     * @param time
     * @param timeUnit
     * @return
     */
    public boolean hmSet(String key, Map<String, Object> map, long time, TimeUnit timeUnit) {
        return rdsHashTool.hmSet(key, map, time, timeUnit);
    }

    /**
     * Hash-删除对象字段
     *
     * @param key
     * @param item
     * @return
     */
    public Long hDel(String key, Object... item) {
        return rdsHashTool.hDel(key, item);
    }

    /**
     * Hash-判断对象字段是否存在
     *
     * @param key
     * @param item
     * @return
     */
    public boolean hHasKey(String key, String item) {
        return rdsHashTool.hHasKey(key, item);
    }

    /**
     * Hash-获取对象指定字段长度
     *
     * @param key
     * @param item
     * @return
     */
    public Long hLen(String key, String item) {
        return rdsHashTool.hLen(key, item);
    }

    /**
     * Hash-对象字段递增
     *
     * @param key
     * @param item
     * @param by
     * @return
     */
    public long hIncr(String key, String item, long by) {
        return rdsHashTool.hIncr(key, item, by);
    }

    /**
     * Hash-对象字段递减
     *
     * @param key
     * @param item
     * @param by
     * @return
     */
    public double hDecr(String key, String item, double by) {
        return rdsHashTool.hDecr(key, item, by);
    }

    //================================第3部分:Hash end=================================


    //================================第4部分:List start=================================

    /**
     * List-通过start-end获取元素集合
     *
     * @param key
     * @param start 开始
     * @param end   结束  0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        return rdsListTool.lGet(key, start, end);
    }

    /**
     * List-右边弹出(倒着取),左边压入
     *
     * @param sourceKey
     * @param destinationKey
     * @param limit
     * @return 弹出的元素
     */
    public List<Object> rightPopAndLeftPush(String sourceKey, String destinationKey, int limit) {
        return rdsListTool.rightPopAndLeftPush(sourceKey, destinationKey, limit);
    }

    /**
     * List-从左边弹出多个元素
     *
     * @param key
     * @param limit
     * @return 弹出的元素
     */
    public List<Object> lLeftMultiPop(String key, int limit) {
        return rdsListTool.lLeftMultiPop(key, limit);
    }

    /**
     * List-从左边弹出一个元素
     *
     * @param key
     * @return 弹出的元素
     */
    public Object lLeftPop(String key) {
        return rdsListTool.lLeftPop(key);
    }

    /**
     * List-获取List长度
     *
     * @param key
     * @return
     */
    public long lGetListSize(String key) {
        return rdsListTool.lGetListSize(key);
    }

    /**
     * List-获取指定下标的元素
     *
     * @param key
     * @param index
     * @return
     */
    public Object lGetByIndex(String key, long index) {
        return rdsListTool.lGetByIndex(key, index);
    }

    /**
     * List-从左边压入元素
     *
     * @param key
     * @param value
     * @return
     */
    public boolean lLeftPush(String key, Object value) {
        return rdsListTool.lLeftPush(key, value);
    }

    /**
     * List-从左边压入元素
     *
     * @param key
     * @param value
     * @param time
     * @return
     */
    public boolean lLeftPush(String key, Object value, long time) {
        return rdsListTool.lLeftPush(key, value, time);
    }

    /**
     * List-从左边压入元素
     *
     * @param key
     * @param value
     * @param time
     * @param timeUnit
     * @return
     */
    public boolean lLeftPush(String key, Object value, long time, TimeUnit timeUnit) {
        return rdsListTool.lLeftPush(key, value, time, timeUnit);
    }

    /**
     * List-从右边压入元素
     *
     * @param key
     * @param value
     * @return
     */
    public boolean lRightPush(String key, Object value) {
        return rdsListTool.lRightPush(key, value);
    }

    /**
     * List-从右边压入元素
     *
     * @param key
     * @param value
     * @param time
     * @return
     */
    public boolean lRightPush(String key, Object value, long time) {
        return rdsListTool.lRightPush(key, value, time);
    }

    /**
     * List-从右边压入元素
     *
     * @param key
     * @param value
     * @param time
     * @return
     */
    public boolean lRightPush(String key, Object value, long time, TimeUnit timeUnit) {
        return rdsListTool.lRightPush(key, value, time, timeUnit);
    }

    /**
     * List-从右边压入多个元素
     *
     * @param key
     * @param value
     * @return
     */
    public boolean rightPushAll(String key, List<Object> value) {
        return rdsListTool.rightPushAll(key, value);
    }

    /**
     * List-从右边压入多个元素
     *
     * @param key
     * @param value
     * @param time
     * @return
     */
    public boolean rightPushAll(String key, List<Object> value, long time) {
        return rdsListTool.rightPushAll(key, value, time);
    }

    /**
     * List-从右边压入多个元素
     *
     * @param key
     * @param value
     * @param time
     * @param timeUnit
     * @return
     */
    public boolean rightPushAll(String key, List<Object> value, long time, TimeUnit timeUnit) {
        return rdsListTool.rightPushAll(key, value, time, timeUnit);
    }

    /**
     * List-根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateByIndex(String key, long index, Object value) {
        return rdsListTool.lUpdateByIndex(key, index, value);
    }

    /**
     * List-移除N个值为value的元素
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        return rdsListTool.lRemove(key, count, value);
    }

    //================================第4部分:List end=================================

    //================================第5部分:Set start=================================

    /**
     * Set-获取Set中的元素数
     *
     * @param key
     * @return
     */
    public Long sSize(String key) {
        return rdsSetTool.sSize(key);
    }

    /**
     * Set-获取Set中的所有元素
     *
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key) {
        return rdsSetTool.sGet(key);
    }

    /**
     * Set-随机弹出一个元素
     *
     * @param key 键
     * @return 弹出的元素
     */
    public Object sPop(String key) {
        return rdsSetTool.sPop(key);
    }

    /**
     * Set-存入多个元素
     *
     * @param key  键
     * @param list
     * @return 成功个数
     */
    public long sSetList(String key, List<Object> list) {
        return rdsSetTool.sSetList(key, list);
    }

    /**
     * Set-存入多个元素
     *
     * @param key
     * @param list
     * @param time
     * @return
     */
    public long sSetList(String key, List<Object> list, long time) {
        return rdsSetTool.sSetList(key, list, time);
    }

    /**
     * Set-存入多个元素
     *
     * @param key
     * @param list
     * @param time
     * @param timeUnit
     * @return
     */
    public long sSetList(String key, List<Object> list, long time, TimeUnit timeUnit) {
        return rdsSetTool.sSetList(key, list, time, timeUnit);
    }

    /**
     * Set-批量存入多个元素
     *
     * @param key
     * @param list
     * @return
     */
    public boolean sPipeSetList(String key, List<Object> list) {
        return rdsSetTool.sPipeSetList(key, list);
    }

    /**
     * Set-判断成员元素是否是集合的成员
     *
     * @param key
     * @param value
     * @return
     */
    public boolean sIsMember(String key, Object value) {
        return rdsSetTool.sIsMember(key, value);
    }

    /**
     * Set-查询两个集合的交集
     *
     * @param key1
     * @param key2
     * @return
     */
    public Set<Object> sInter(String key1, String key2) {
        return rdsSetTool.sInter(key1, key2);
    }

    /**
     * Set-查询两个集合的交集, 并存储于其他key上
     *
     * @param key1
     * @param key2
     * @param storeKey
     * @return
     */
    public Long sInterAndStore(String key1, String key2, String storeKey) {
        return rdsSetTool.sInterAndStore(key1, key2, storeKey);
    }

    /**
     * Set-移除值为value的元素
     *
     * @param key
     * @param value
     * @return 移除的个数
     */
    public long sSetRemove(String key, Object value) {
        return rdsSetTool.sSetRemove(key, value);
    }

    /**
     * Set-移除多个元素
     *
     * @param key
     * @param list
     * @return 移除的个数
     */
    public long sSetRemove(String key, List<Object> list) {
        return rdsSetTool.sSetRemove(key, list);
    }

    //================================第5部分:Set end=================================

    //================================第6部分:zSet start=================================

    /**
     * ZSet-存入一个元素
     *
     * @param key   键
     * @param value 值
     * @param score 分数(排序序号,asc排序)
     * @return
     */
    public boolean zAdd(String key, Object value, double score) {
        return rdsZSetTool.zAdd(key, value, score);
    }

    /**
     * ZSet-批量存入元素
     *
     * @param key
     * @param set
     * @return
     */
    public Long zAdd(String key, Set<ZSetOperations.TypedTuple<Object>> set) {
        return rdsZSetTool.zAdd(key, set);
    }

    /**
     * ZSet-批量存入元素
     *
     * @param key
     * @param valueMap Object=元素值;Double=分数
     * @return
     */
    public Long zAdd(String key, Map<Object, Double> valueMap) {
        return rdsZSetTool.zAdd(key, valueMap);
    }

    /**
     * ZSet-对比两个有序集合的交集并将结果集存储在新的有序集合dest中
     *
     * @param key2 键1
     * @param key2 键2
     * @return 成功个数
     */
    public long zInterAndStore(String key1, String key2, String destKey) {
        return rdsZSetTool.zInterAndStore(key1, key2, destKey);
    }

    /**
     * ZSet-获取zSet长度
     *
     * @param key 键
     * @return 长度
     */
    public long zSize(String key) {
        return rdsZSetTool.zSize(key);
    }

    /**
     * ZSet-获取zSet指定区间分数的成员数
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public long zCount(String key, Double min, Double max) {
        return rdsZSetTool.zCount(key, min, max);
    }

    /**
     * ZSet-获取元素分数值
     *
     * @param key   键
     * @param value 值
     * @return 分数值
     */
    public Double zScore(String key, Object value) {
        return rdsZSetTool.zScore(key, value);
    }

    /**
     * ZSet-返回指定成员的下标值
     *
     * @param key 键
     * @param obj 元素
     * @return 下标值
     */
    public Long zRank(String key, Object obj) {
        return rdsZSetTool.zRank(key, obj);
    }

    /**
     * ZSet-返回指定成员的下标值(从后往前取)
     *
     * @param key 键
     * @param obj 元素
     * @return 下标值
     */
    public Long zReverseRank(String key, Object obj) {
        return rdsZSetTool.zReverseRank(key, obj);
    }

    /**
     * ZSet-判断是否存在指定元素
     *
     * @param key 键
     * @param obj 元素
     * @return true存在 false不存在
     */
    public boolean zHasElement(String key, Object obj) {
        return rdsZSetTool.zHasElement(key, obj);
    }

    /**
     * ZSet-获取指定下标的元素
     *
     * @param key
     * @param index
     * @return
     */
    public Object zGetByIndex(String key, long index) {
        return rdsZSetTool.zGetByIndex(key, index);
    }

    /**
     * ZSet-根据索引区间获取zSet列表
     *
     * @param start 开始索引
     * @param end   结束索引 -1查询全部
     * @return zSet列表
     */
    public LinkedHashSet<Object> zRange(String key, long start, long end) {
        return rdsZSetTool.zRange(key, start, end);
    }

    /**
     * ZSet-根据索引区间获取zSet列表(从后往前取)
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public LinkedHashSet<Object> zRevRange(String key, long start, long end) {
        return rdsZSetTool.zRevRange(key, start, end);
    }

    /**
     * ZSet-根据分数区间获取Set列表
     *
     * @param min 开始分数
     * @param max 结束分数
     * @return
     */
    public LinkedHashSet<Object> zRangeByScore(String key, double min, double max) {
        return rdsZSetTool.zRangeByScore(key, min, max);
    }

    /**
     * ZSet-根据下标区间获取Set列表(返回元素、分数值)
     *
     * @param start 开始下标
     * @param end   结束下标
     * @return
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScores(String key, long start, long end) {
        return rdsZSetTool.zRangeWithScores(key, start, end);
    }

    /**
     * ZSet-根据分数区间获取Set列表(返回元素、分数值)
     *
     * @param min 开始分数
     * @param max 结束分数
     * @return
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRangeByScoreWithScores(String key, double min, double max) {
        return rdsZSetTool.zRangeByScoreWithScores(key, min, max);
    }

    /**
     * ZSet-根据分数区间获取Set列表(返回元素、分数值),再从下标offset开始,取count个元素
     *
     * @param key
     * @param min    开始分数
     * @param max    结束分数
     * @param offset 下标开始值
     * @param count  取元素的数量
     * @return
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRangeByScoreWithScores(String key, double min, double max, long offset, long count) {
        return rdsZSetTool.zRangeByScoreWithScores(key, min, max, offset, count);
    }

    /**
     * ZSet-根据分数区间获取Set列表(返回元素、分数值),再从下标offset开始,取count个元素(从后往前取)
     *
     * @param key
     * @param min    开始分数
     * @param max    结束分数
     * @param offset 下标开始值
     * @param count  取元素的数量
     * @return
     */
    public Set<ZSetOperations.TypedTuple<Object>> zRevRangeByScoreWithScores(String key, double min, double max, long offset, long count) {
        return rdsZSetTool.zRevRangeByScoreWithScores(key, min, max, offset, count);
    }

    /**
     * ZSet-增加元素分数值
     *
     * @param key   键
     * @param value 值
     * @param delta 增量值
     * @return
     */
    public Double zIncrScore(String key, Object value, double delta) {
        return rdsZSetTool.zIncrScore(key, value, delta);
    }

    /**
     * ZSet-删除元素
     *
     * @param key
     * @param object
     * @return
     */
    public Long zRemove(String key, Object object) {
        return rdsZSetTool.zRemove(key, object);
    }

    /**
     * ZSet-批量删除元素
     *
     * @param key
     * @param list
     * @return
     */
    public Long zRemove(String key, List<Object> list) {
        return rdsZSetTool.zRemove(key, list);
    }

    //================================第6部分:zSet end=================================

    //================================第7部分:GEO start=================================

    /**
     * GEO-添加成员经纬度
     *
     * @param key    键
     * @param member 成员
     * @param lng    经度
     * @param lat    纬度
     * @return 成功数量
     */
    public Long geoAdd(String key, Object member, double lng, double lat) {
        return rdsGeoTool.geoAdd(key, member, lng, lat);
    }

    /**
     * GEO-获取成员经纬度
     *
     * @param key    键
     * @param member 成员
     * @return 经纬度
     */
    public Point geoPosition(String key, Object member) {
        return rdsGeoTool.geoPosition(key, member);
    }

    /**
     * GEO-获取一批成员的经纬度
     *
     * @param key  键
     * @param list 成员列表
     * @return 经纬度列表
     */
    public List<Point> geoPositions(String key, List<Object> list) {
        return rdsGeoTool.geoPositions(key, list);
    }

    /**
     * GEO-计算两个成员间的距离
     *
     * @param key     键
     * @param member1 成员1
     * @param member2 成员2
     * @return 距离
     */
    public Distance geoDistance(String key, Object member1, Object member2) {
        return rdsGeoTool.geoDistance(key, member1, member2);
    }

    /**
     * GEO-计算两个成员间的距离
     *
     * @param key
     * @param member1
     * @param member2
     * @param metrics
     * @return
     */
    public Distance geoDistance(String key, Object member1, Object member2, Metrics metrics) {
        return rdsGeoTool.geoDistance(key, member1, member2, metrics);
    }

    /**
     * GEO-获取指定成员周围的成员列表
     *
     * @param key
     * @param member
     * @param value
     * @param metrics
     * @return
     */
    public List<Object> geoRadius(String key, Object member, double value, Metrics metrics) {
        return rdsGeoTool.geoRadius(key, member, value, metrics);
    }

    //================================第7部分:GEO end=================================
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/561597.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STL-常用算法(二.拷贝 替换 算术 集合)

开篇先附上STL-常用算法(一)的链接 STL-常用算法&#xff08;一.遍历 查找 排序&#xff09;_小梁今天敲代码了吗的博客-CSDN博客 目录 常用拷贝和替换算法&#xff1a; copy函数示例&#xff1a;&#xff08;将v1容器中的元素复制给v2&#xff09; replace函数示例&#…

06:冯诺依曼计算机

布尔代数&#xff1a;是现代电子计算机的数学和逻辑基础 ---------- 布尔代数与开关电路&#xff1a; ---------- 1945年&#xff1a;冯诺依曼101报告 硬件&#xff0c;操作系统软件、防病毒软件、办公软件、日程生活娱乐软件...... 冯诺依曼体系结构&#xff1a; 算术逻辑单…

chatgpt赋能Python-python_pu__

Python pu()函数介绍及使用方法 在Python编程中&#xff0c;pu()函数是一个常用的输出函数&#xff0c;可以将输出的内容打印到控制台上。在这篇文章中&#xff0c;我们将探讨pu()函数的具体用法以及它在Python编程中的实际应用。 什么是pu()函数 pu()函数是Python标准库中的…

Nacos、Eureka和Zookeeper有什么区别

Nacos、Eureka和Zookeeper都是服务注册中心&#xff0c;它们的主要功能是管理分布式系统中各个微服务实例的注册与发现。它们之间的主要区别在于&#xff1a; 1. 语言支持&#xff1a;Nacos是用Java语言开发的&#xff0c;Eureka是用Java语言开发的&#xff0c;Zookeeper则是用…

MySQL高级篇——覆盖索引、前缀索引、索引下推、SQL优化、主键设计

导航&#xff1a; 【Java笔记踩坑汇总】Java基础进阶JavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线MySQL高级篇设计模式牛客面试题 目录 8. 优先考虑覆盖索引 8.1 什么是覆盖索引&#xff1f; 8.1.0 概念 8.0.1 覆盖索引情况下&#xff0c;“不等于”…

chatgpt赋能Python-python_pythoncom

Python与Pythoncom&#xff1a;为您的SEO提供强大的支持 Python是一种经过广泛应用的高级编程语言&#xff0c;可用于多种应用程序的开发&#xff0c;包括爬虫、机器学习、数据分析、Web开发等等。而Pythoncom则是用于与Windows系统进行交互的Python模块&#xff0c;可以实现与…

小航编程题库机器人等级考试理论一级(2022年12月) (含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;_程序猿下山的博客-CSDN博客 单选题2.0分 删除编辑 答案:C 第1题下列哪个是机器人?&#xff08; &#xff09; A、aB、bC、cD、d 答案解析&#xff1a; 单选题…

小航编程题库机器人等级考试理论一级(2022年6月) (含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;_程序猿下山的博客-CSDN博客 单选题2.0分 删除编辑 答案:D 第1题下列哪个选项属于机器人&#xff1f;&#xff08;?&#xff09; A、aB、bC、cD、d 答案解析&a…

MySQL第一章、MySQL安装与配置

目录 一、数据库介绍 1.1什么是数据库 1.2数据库分类 1.3数据库编程 1.4其他客户端 ​1.5MySQL总结 一、数据库介绍 1.1什么是数据库 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件保存数据有以下几个缺点&#xff1a; 文件的安全性问题文件不利于数…

chatgpt赋能Python-python_plup

Python Plug-In: 如何让你的Python代码更加高效&#xff1f; Python是一种高级编程语言&#xff0c;它的代码易于阅读和编写&#xff0c;通常是程序员的首选语言之一。但是&#xff0c;Python本身并不能满足所有需求&#xff0c;如果需要做一些复杂的任务&#xff0c;就需要使…

物联网应用的全球最低功耗无线芯片——芝麻芯片和大米天线

今天的内容是两则科技新闻&#xff0c;“用于物联网应用的全球最低功耗的无线芯片”&#xff0c;和“一款多频段微型芯片天线”。由于芯片的面积分别为1平方毫米&#xff0c;和21平方毫米&#xff0c;差不多是1粒芝麻和2粒大米的大小&#xff0c;故称为芝麻芯片和大米天线。 0…

easypan部署记录

文章目录 项目部署学习链接1.安装ffmpeglinux centos下安装ffmpeg的详细教程 2. springboot maven 多环境配置文件pom.xmlapplication.propertiesapplication-dev.propertiesapplication-prod.propertieslogback.xml 3. 配置nginx配置要点nginx配置 4. 启动项目5.访问 项目部署…

Java --- 云尚办公之权限管理模块

目录 一、权限管理 二、JWT 三、用户登录功能实现 四、用户登录后的信息 五、前端代码 六、spring-security 6.1、用户认证 6.2、用户授权 一、权限管理 粗粒度权限&#xff1a; 不同用户进入系统&#xff0c;因权限不同看到菜单不同 细粒度权限&#xff1a; 在一个页…

一、尚医通平台前端搭建

文章目录 一、尚医通平台前端搭建1、服务端渲染技术NUXT 二、首页实现1、公共处理1.1添加静态资源1.2 定义布局1.2.1 修改默认布局1.2.2 提取头文件1.2.3 提取尾文件1.2.4 默认布局引入头尾文件 2、首页引入2.1 引入首页静态页面2.2 首页数据分析 3、首页数据api接口3.1 医院分…

chatgpt赋能Python-python_penup怎么用

Python Penup - 内在交互性的有用工具 Python编程语言的流行一直与其灵活性和易于使用性息息相关。除此之外&#xff0c;Python还提供了大量的扩展和库&#xff0c;以满足各种编程需求。Penup是Python编程中一个非常有用的工具。 什么是Python Penup&#xff1f; Penup是Pyt…

windows环境下安装RabbitMQ(超详细),

windows环境下安装RabbitMQ&#xff08;超详细&#xff09; 注&#xff1a;安装路径&#xff0c;用户名均为英文 一、RabbitMq简介 1.1消息队列中间件简介 消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用耦合&#xff0c;异步消息&#xff0c;流量削锋等问题…

Discourse 如何配置 MAXMIND 来对 IP 地址反向查询

【配置 MAXMIND&#xff0c;Discourse 需要重新构建&#xff0c;这将会导致服务中断。 】 什么是 MAXMIND 和为什么我们需要使用这个服务 Discourse 使用 MAXMIND 来通过 IP 地址反向查询具体的物理地址。 如果 Discourse 没有配置 Maxmind’s 数据库&#xff0c;我们看到的配…

leetcode 数据库题 196,197,262,511,550,570

leetcode 数据库题第二弹 196. 删除重复的电子邮箱197. 上升的温度262. 行程和用户511. 游戏玩法分析 I550. 游戏玩法分析 IV570. 至少有5名直接下属的经理577. 员工奖金小结 196. 删除重复的电子邮箱 题目地址&#xff1a;https://leetcode.cn/problems/delete-duplicate-emai…

二、服务网关-Gateway

文章目录 一、服务网关1、网关介绍2、Spring Cloud Gateway介绍3、搭建server-gateway模块3.1 搭建server-gateway3.2 修改配置pom.xml3.3 在resources下添加配置文件3.4添加启动类3.5 跨域处理3.5.1 为什么有跨域问题&#xff1f;3.5.2解决跨域问题 3.6服务调整3.7测试 一、服…

chatgpt赋能Python-python_pulp包怎么安装

Python Pulp包的安装方法 如果你正在进行线性规划或整数规划问题的研究或解决&#xff0c;那么Python Pulp包是一个非常实用的工具&#xff0c;它可以快速、高效地解决这些问题。但是&#xff0c;在使用Python Pulp包的过程中&#xff0c;你可能会遇到一些安装问题。本文将介绍…