SpringBoot 整合Redis

1. Maven 依赖引入

​ Maven 依赖的引入。

<!--  引入Redis依赖  -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--  Redis连接池依赖 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<!--  Redis序列化依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.75</version>
</dependency>
打开spring-boot-starter-data-redis可以查看其依赖了spring-data-redis,lettuce。

说明:在SpringBoot 2.x之后,原来使用的jedis被替换成lettuce。

​ jedis:采用直连,多个线程操作不安全。要避免不安全,使用jedis pool 连接池技术。

​ lettuce:采用netty,异步请求,实例可以在多个线程中共享,不存在线程不安全,可以减少线程数量。

<dependency>
  <groupId>org.springframework.data</groupId>
  <artifactId>spring-data-redis</artifactId>
  <version>2.5.1</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>io.lettuce</groupId>
  <artifactId>lettuce-core</artifactId>
  <version>6.1.2.RELEASE</version>
  <scope>compile</scope>
</dependency>

2. Redis 配置

2.1 配置分析(源码分析)

​ SpringBoot所有的配置类都有一个自动配置类,自动配置类都对绑定一个 properties 配置文件,最后会绑定到application.properties.

找到 spring-boot-autoconfigure包下的META-INF目录下的spring.factories文件,查看Redis配置类。

在这里插入图片描述

配置类如下:


@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class}) //使 使用 @ConfigurationProperties 注解的类生效。
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean( //若自定义了名为redisTemplate的Bean,则下面的自动配置的模板失效
        name = {"redisTemplate"}
    )
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    //@ConditionalOnSingleCandidate表示当指定Bean在容器中只有一个,或者虽然有多个但是指定首选Bean(@Primary),才会生成此		Bean.
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 采用默认的RedisTemplate没有过多的设置(没有设置序列化),redis对象需要序列化!
        // 两个范型都是 Object, 我们更新经常需要使用的是 <String,Obejct> => 自己定义一个RedisTemplate
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean //由于String类型是redis中最常使用的类型,所以单独提出来一个bean
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

@ConfigurationProperties(
    prefix = "spring.redis" //指定对应properties文件配置的前缀
)
public class RedisProperties {
    private int database = 0;
    private String url;
    private String host = "localhost";
    private String username;
    private String password;
    private int port = 6379;
    private boolean ssl;
    private Duration timeout;
    private Duration connectTimeout;
    private String clientName;
    private RedisProperties.ClientType clientType;
    private RedisProperties.Sentinel sentinel;
    private RedisProperties.Cluster cluster; //集群配置
    private final RedisProperties.Jedis jedis = new RedisProperties.Jedis();
    private final RedisProperties.Lettuce lettuce = new RedisProperties.Lettuce();

2.2 序列化配置

​ 默认的RedisTemplate使用java默认的序列化方法,方法产生乱码。

127.0.0.1:6379> KEYS *
1) "\xac\xed\x00\x05t\x00\x011"  //默认的序列化方法产生乱码

​ 源码分析默认的配置, 修改它来自定义配置序列化方法。

在这里插入图片描述
在这里插入图片描述

2.3 自定义序列化配置

​ 新建config目录放置所有配置类,新建RedisConfig类来自定义化Redis配置。

​ 使用fastJson序列化,导入依赖。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.75</version>
</dependency>

​ 新建RedisConfig类,自定义序列化器

/**
 *  Value序列化器
 */
class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
    private final Class<T> clazz;

    FastJsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }
    
    /**
     * Serialize the given object to binary data.
     *
     * @param t object to serialize. Can be {@literal null}.
     * @return the equivalent binary data. Can be {@literal null}.
     */
    @Override
    public byte[] serialize(T t) throws SerializationException {
       if(t == null){
           return new byte[0];
       }
       return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);
    }

    /**
     * Deserialize an object from the given binary data.
     *
     * @param bytes object binary representation. Can be {@literal null}.
     * @return the equivalent object instance. Can be {@literal null}.
     */
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
       if(bytes == null || bytes.length <=0){
           return null;
       }
       String str = new String(bytes,StandardCharsets.UTF_8);
       return JSON.parseObject(str,clazz);
    }
}

/**
 *  Key序列化器
 */
class StringRedisSerializer implements RedisSerializer<Object>{
    private final Charset charset; // 编码
    StringRedisSerializer(){ this(StandardCharsets.UTF_8); }
    private StringRedisSerializer(Charset charset) {
        Assert.notNull(charset,"Charset must not be null!");
        this.charset = charset;
    }

    /**
     * Serialize the given object to binary data.
     *
     * @param object object to serialize. Can be {@literal null}.
     * @return the equivalent binary data. Can be {@literal null}.
     */
    @Override
    public byte[] serialize(Object object) throws SerializationException {
        String string = JSON.toJSONString(object);
        if(StringUtil.isNullOrEmpty(string)){
            return null;
        }
        string = string.replace("\"","");
        return string.getBytes(charset);
    }

    /**
     * Deserialize an object from the given binary data.
     *
     * @param bytes object binary representation. Can be {@literal null}.
     * @return the equivalent object instance. Can be {@literal null}.
     */
    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
        return (bytes == null ? null:new String(bytes,charset));
    }
}

2.4 自定义序列化模板

​ 使用 上面自定义的序列化器自定义序列化模板。

@Bean(name = "redisTemplate")
public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
    RedisTemplate<Object,Object> template = new RedisTemplate<>();
    //Value序列化方法
    FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
    //Value值采用 FastJsonRedisSerializer
    template.setValueSerializer(fastJsonRedisSerializer);
    template.setHashValueSerializer(fastJsonRedisSerializer);
    //Key序列化方法
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    //Key值采用 StringRedisSerializer
    template.setKeySerializer(stringRedisSerializer);
    template.setHashKeySerializer(stringRedisSerializer);
    // 全局开启AutoType,这里方便开发,使用全局模式
    ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
    // 建议使用这种方式,小范围指定白名单
    //ParserConfig.getGlobalInstance().addAccept("com.xxx.xxx");
    template.setConnectionFactory(redisConnectionFactory);
    template.afterPropertiesSet();
    return template;
}

2.5 配置Spring Cache + Redis

​ 当引入了 Redis 后, Spring Cache 默认就使用 Redis 做为缓存。因为Redis 默认配置 产生了 RedisCacheManager 的Bean。此时Spring 缓存在 Redis 里,但是默认的序列化器是默认的。因此Redis中存储的Spring缓存中存在字节乱码,不便于查看。因此需要配置也使用fastJson序列器。

在这里插入图片描述

​ 配置如下:

@Configuration
public class RedisConfig extends CachingConfigurerSupport {


    /**
     * 设置 Redis数据默认过期时间, 默认6小时(不会影响正常 Redis 的过期时间)
     * 设置 @cacheable 序列化方式 (spring cache 序列化方式)
     */
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(){
        // Value 序列化器
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
        configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer));
        // 默认 Spring Cache 使用 Redis 的过期时间是 6小时 (不会影响正常 Redis 的过期时间)
        configuration = configuration.entryTtl(Duration.ofHours(6));
        return configuration;
    }
    ...
}

​ 结果如下: 产生了新的redisCacheConfiguration Bean 覆盖了默认的 Bean。

在这里插入图片描述

2.6 自定义Spring Cache 的KeyGenerator

​ 关于 KeyGenerator , 见 SpringCache.md 。

@Configuration
public class RedisConfig extends CachingConfigurerSupport {

....

/**
 *  自定义缓存 key 生成策略( Spring Cache )
 */
@Bean
@Override
public KeyGenerator keyGenerator() {
    return (target, method, params) -> {
        Map<String,Object> container = new HashMap<>(3);
        Class<?> targetClass = target.getClass();
        // 类地址
        container.put("class",targetClass.toGenericString());
        // 方法名称
        container.put("methodName",method.getName());
        // 包名称
        container.put("package",targetClass.getPackage());
        // 参数列表
        for(int i=0; i<params.length; i++){
            container.put(String.valueOf(i),params[i]);
        }
        // 转为 JSON 字符串
        String jsonString = JSON.toJSONString(container);
        // 做 SHA256 哈希得到一个 SHA256 摘要作为 key
        return DigestUtils.sha256Hex(jsonString);
    };
}
...
}

2.7 RedisConfig 配置源代码

package com.example.springcache.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import io.netty.util.internal.StringUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.util.Assert;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class RedisConfig extends CachingConfigurerSupport {


    /**
     * 设置 Redis数据默认过期时间, 默认6小时(不会影响正常 Redis 的过期时间)
     * 设置 @cacheable 序列化方式 (spring cache 序列化方式)
     */
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(){
        // Value 序列化器
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
        configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer));
        // 默认 Spring Cache 使用 Redis 的过期时间是 6小时 (不会影响正常 Redis 的过期时间)
        configuration = configuration.entryTtl(Duration.ofHours(6));
        return configuration;
    }



    /*
     * 重写 RedisTemplate
     */
    @Bean(name = "redisTemplate")
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<Object,Object> template = new RedisTemplate<>();
        //Value序列化方法
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        //Value值采用 FastJsonRedisSerializer
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);
        //Key序列化方法
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //Key值采用 StringRedisSerializer
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        // 全局开启AutoType,这里方便开发,使用全局模式
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        // 建议使用这种方式,小范围指定白名单
        //ParserConfig.getGlobalInstance().addAccept("com.xxx.xxx");
        template.setConnectionFactory(redisConnectionFactory);
        template.afterPropertiesSet();
        return template;
    }


    /**
     *  自定义缓存 key 生成策略( Spring Cache )
     */
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            Map<String,Object> container = new HashMap<>(3);
            Class<?> targetClass = target.getClass();
            // 类地址
            container.put("class",targetClass.toGenericString());
            // 方法名称
            container.put("methodName",method.getName());
            // 包名称
            container.put("package",targetClass.getPackage());
            // 参数列表
            for(int i=0; i<params.length; i++){
                container.put(String.valueOf(i),params[i]);
            }
            // 转为 JSON 字符串
            String jsonString = JSON.toJSONString(container);
            // 做 SHA256 哈希得到一个 SHA256 摘要作为 key
            return DigestUtils.sha256Hex(jsonString);
        };
    }

    /**
     *  Value序列化器
     */
    class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
        private final Class<T> clazz;

        FastJsonRedisSerializer(Class<T> clazz) {
            super();
            this.clazz = clazz;
        }

        /**
         * Serialize the given object to binary data.
         *
         * @param t object to serialize. Can be {@literal null}.
         * @return the equivalent binary data. Can be {@literal null}.
         */
        @Override
        public byte[] serialize(T t) throws SerializationException {
           if(t == null){
               return new byte[0];
           }
           return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);
        }

        /**
         * Deserialize an object from the given binary data.
         *
         * @param bytes object binary representation. Can be {@literal null}.
         * @return the equivalent object instance. Can be {@literal null}.
         */
        @Override
        public T deserialize(byte[] bytes) throws SerializationException {
           if(bytes == null || bytes.length <=0){
               return null;
           }
           String str = new String(bytes,StandardCharsets.UTF_8);
           return JSON.parseObject(str,clazz);
        }
    }

    /**
     *  Key序列化器
     */
    class StringRedisSerializer implements RedisSerializer<Object>{
        private final Charset charset; // 编码
        StringRedisSerializer(){ this(StandardCharsets.UTF_8); }
        private StringRedisSerializer(Charset charset) {
            Assert.notNull(charset,"Charset must not be null!");
            this.charset = charset;
        }

        /**
         * Serialize the given object to binary data.
         *
         * @param object object to serialize. Can be {@literal null}.
         * @return the equivalent binary data. Can be {@literal null}.
         */
        @Override
        public byte[] serialize(Object object) throws SerializationException {
            String string = JSON.toJSONString(object);
            if(StringUtil.isNullOrEmpty(string)){
                return null;
            }
            string = string.replace("\"","");
            return string.getBytes(charset);
        }

        /**
         * Deserialize an object from the given binary data.
         *
         * @param bytes object binary representation. Can be {@literal null}.
         * @return the equivalent object instance. Can be {@literal null}.
         */
        @Override
        public Object deserialize(byte[] bytes) throws SerializationException {
            return (bytes == null ? null:new String(bytes,charset));
        }
    }
}

3. RedisUtils 编写

3.1 依赖

<!--    断言 (RedisUtils使用了其中的一些工具类)    -->
<dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
</dependency>

​ 将常用的方法集合写成 RedisUtils 工具类。

3.2 RedisUtils 源码

/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.example.springcache.utils;


import org.assertj.core.util.Lists;
import org.assertj.core.util.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;


@Component
@SuppressWarnings({"unchecked", "all"})
public class RedisUtils {
    private static final Logger log = LoggerFactory.getLogger(RedisUtils.class);
    private RedisTemplate<Object, Object> redisTemplate;
    public RedisUtils(RedisTemplate<Object, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
        return true;
    }

    /**
     * 指定缓存失效时间
     *
     * @param key      键
     * @param time     时间
     * @param timeUnit 单位
     */
    public boolean expire(String key, long time, TimeUnit timeUnit) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, timeUnit);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
        return true;
    }

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

    /**
     * 查找匹配key
     *
     * @param pattern key
     * @return /
     */
    public List<String> scan(String pattern) {
        ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
        RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
        RedisConnection rc = Objects.requireNonNull(factory).getConnection();
        Cursor<byte[]> cursor = rc.scan(options);
        List<String> result = new ArrayList<>();
        while (cursor.hasNext()) {
            result.add(new String(cursor.next()));
        }
        try {
            RedisConnectionUtils.releaseConnection(rc, factory);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return result;
    }

    /**
     * 分页查询 key
     *
     * @param patternKey key
     * @param page       页码
     * @param size       每页数目
     * @return /
     */
    public List<String> findKeysForPage(String patternKey, int page, int size) {
        ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();
        RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
        RedisConnection rc = Objects.requireNonNull(factory).getConnection();
        Cursor<byte[]> cursor = rc.scan(options);
        List<String> result = new ArrayList<>(size);
        int tmpIndex = 0;
        int fromIndex = page * size;
        int toIndex = page * size + size;
        while (cursor.hasNext()) {
            if (tmpIndex >= fromIndex && tmpIndex < toIndex) {
                result.add(new String(cursor.next()));
                tmpIndex++;
                continue;
            }
            // 获取到满足条件的数据后,就可以退出了
            if (tmpIndex >= toIndex) {
                break;
            }
            tmpIndex++;
            cursor.next();
        }
        try {
            RedisConnectionUtils.releaseConnection(rc, factory);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return result;
    }

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

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    public void del(String... keys) {
        if (keys != null && keys.length > 0) {
            if (keys.length == 1) {
                boolean result = redisTemplate.delete(keys[0]);
                log.debug("--------------------------------------------");
                log.debug(new StringBuilder("删除缓存:").append(keys[0]).append(",结果:").append(result).toString());
                log.debug("--------------------------------------------");
            } else {
                Set<Object> keySet = new HashSet<>();
                for (String key : keys) {
                    keySet.addAll(redisTemplate.keys(key));
                }
                long count = redisTemplate.delete(keySet);
                log.debug("--------------------------------------------");
                log.debug("成功删除缓存:" + keySet.toString());
                log.debug("缓存删除数量:" + count + "个");
                log.debug("--------------------------------------------");
            }
        }
    }

    // ============================String=============================

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

    /**
     * 批量获取
     *
     * @param keys
     * @return
     */

    /**
     * 批量获取
     *
     * @param keys
     * @return
     */
    public List<Object> multiGet(List<String> keys) {
        List list = redisTemplate.opsForValue().multiGet(Sets.newHashSet(keys));
        List resultList = Lists.newArrayList();
        Optional.ofNullable(list).ifPresent(e-> list.forEach(ele-> Optional.ofNullable(ele).ifPresent(resultList::add)));
        return resultList;
    }

    /**
     * 普通缓存放入
     *
     * @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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key      键
     * @param value    值
     * @param time     时间
     * @param timeUnit 类型
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, timeUnit);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

    // ================================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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            return 0;
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @param key 键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            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) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

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

    /**
     * @param prefix 前缀
     * @param ids    id
     */
    public void delByKeys(String prefix, Set<Long> ids) {
        Set<Object> keys = new HashSet<>();
        for (Long id : ids) {
            keys.addAll(redisTemplate.keys(new StringBuffer(prefix).append(id).toString()));
        }
        long count = redisTemplate.delete(keys);
        // 此处提示可自行删除
        log.debug("--------------------------------------------");
        log.debug("成功删除缓存:" + keys.toString());
        log.debug("缓存删除数量:" + count + "个");
        log.debug("--------------------------------------------");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值