【SpringBoot整合系列】SpringBoot整合Redis[附redis工具类源码]

目录

SpringBoot整合Redis

1.下载和安装Redis

略,可以看我之前的博客

2.新建工程,导入依赖

其中主要是redis依赖

xml 复制代码
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>3.0.3</version>
            <scope>test</scope>
        </dependency>

3.添加配置

  • 两个重要的API:RedisTemplate 和 StringRedisTemplate
  • RedisTemplate 和 StringRedisTemplate提供了一系列opsForXxx()方法,返回XxxOperations对象,用来操作Xxx对象。
    • opsForValue():返回可操作String对象的ValueOperations对象;
    • opsForList():返回可操作List对象的ListOperations对象;
    • opsForSet():返回可操作Set对象的SetOperations对象;
    • opsForZset():返回可操作Zset对象的ZsetOperations对象;
    • opsForHash():返回可操作Hash对象的HashOperations对象;
    • ...

4.先来几个基本的示例

测试代码

java 复制代码
package cn.smbms;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;

@SpringBootTest
@Slf4j
class RedisdemoApplicationTests {
    @Resource
    private RedisTemplate<Object, Object> redisTemplate;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Test
    void setAndGetValue() {
        redisTemplate.opsForValue().set("redisName", "张三");
        stringRedisTemplate.opsForValue().set("stringRedisName", "张三");
        log.info("写入两个字符串到Redis中完毕");
        String redisName = (String) redisTemplate.opsForValue().get("redisName");
        String stringRedisName = stringRedisTemplate.opsForValue().get("stringRedisName");
        log.info("从Redis中取出redisName的值是:{}",redisName);
        log.info("从Redis中取出stringRedisName的值是:{}",stringRedisName);
    }
}

输出结果

java 复制代码
......cn.smbms.RedisdemoApplicationTests       : 写入两个字符串到Redis中完毕
......cn.smbms.RedisdemoApplicationTests       : 从Redis中取出redisName的值是:张三
......cn.smbms.RedisdemoApplicationTests       : 从Redis中取出stringRedisName的值是:张三

用redis客户端查看一下存储内容

  • 这些看着像是乱码,其实并不是乱码。
  • RedisTemplate 存储的数据通常是二进制的。Redis 是一个键值存储系统,它存储的值可以是字符串、二进制数据、甚至是序列化的对象。
  • RedisTemplate 是 Spring Data Redis 提供的一个类,用于在 Spring 应用中与 Redis 进行交互。
  • 它提供了一种在 Java 对象和 Redis 数据之间进行序列化和反序列化的机制。
  • 默认情况下,RedisTemplate 使用 JDK 的序列化机制将 Java 对象转换为二进制数据,并存储在 Redis 中。

5.封装redis工具类

  • 直接用RedisTemplate操作Redis,需要很多行代码,因此直接封装好一个RedisUtils,这样写代码更方便点。
  • 这个RedisUtils交给Spring容器实例化,使用时直接注解注入,节省代码,操作统一。

RedisKeyUtil

java 复制代码
package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisKeyUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisKeyUtil.redisTemplate = redisTemplate;
    }
    /** -------------------key相关操作--------------------- */
    /**
     * 删除key
     *
     * @param key
     */
    public static void delete(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 批量删除key
     *
     * @param keys
     */
    public static void delete(Collection<String> keys) {
        redisTemplate.delete(keys);
    }

    /**
     * 序列化key
     *
     * @param key
     * @return
     */
    public static byte[] dump(String key) {
        return redisTemplate.dump(key);
    }

    /**
     * 是否存在key
     *
     * @param key
     * @return
     */
    public static Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param timeout
     * @param unit
     * @return
     */
    public static Boolean expire(String key, long timeout, TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param date
     * @return
     */
    public static Boolean expireAt(String key, Date date) {
        return redisTemplate.expireAt(key, date);
    }

    /**
     * 查找匹配的key
     *
     * @param pattern
     * @return
     */
    public static Set<String> keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * 将当前数据库的 key 移动到给定的数据库 db 当中
     *
     * @param key
     * @param dbIndex
     * @return
     */
    public static Boolean move(String key, int dbIndex) {
        return redisTemplate.move(key, dbIndex);
    }

    /**
     * 移除 key 的过期时间,key 将持久保持
     *
     * @param key
     * @return
     */
    public static Boolean persist(String key) {
        return redisTemplate.persist(key);
    }

    /**
     * 返回 key 的剩余的过期时间
     *
     * @param key
     * @param unit
     * @return
     */
    public static Long getExpire(String key, TimeUnit unit) {
        return redisTemplate.getExpire(key, unit);
    }

    /**
     * 返回 key 的剩余的过期时间
     *
     * @param key
     * @return
     */
    public static Long getExpire(String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * 从当前数据库中随机返回一个 key
     *
     * @return
     */
    public static String randomKey() {
        return redisTemplate.randomKey();
    }

    /**
     * 修改 key 的名称
     *
     * @param oldKey
     * @param newKey
     */
    public static void rename(String oldKey, String newKey) {
        redisTemplate.rename(oldKey, newKey);
    }

    /**
     * 仅当 newkey 不存在时,将 oldKey 改名为 newkey
     *
     * @param oldKey
     * @param newKey
     * @return
     */
    public static Boolean renameIfAbsent(String oldKey, String newKey) {
        return redisTemplate.renameIfAbsent(oldKey, newKey);
    }

    /**
     * 返回 key 所储存的值的类型
     *
     * @param key
     * @return
     */
    public static DataType type(String key) {
        return redisTemplate.type(key);
    }
}

RedisStringUtil

java 复制代码
package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisStringUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisStringUtil.redisTemplate = redisTemplate;
    }
    /** -------------------string相关操作--------------------- */
    /**
     * 设置指定 key 的值
     *
     * @param key
     * @param value
     */
    public static void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 获取指定 key 的值
     *
     * @param key
     * @return
     */
    public static String get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 返回 key 中字符串值的子字符
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static String getRange(String key, long start, long end) {
        return redisTemplate.opsForValue().get(key, start, end);
    }

    /**
     * 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
     *
     * @param key
     * @param value
     * @return
     */
    public static String getAndSet(String key, String value) {
        return redisTemplate.opsForValue().getAndSet(key, value);
    }

    /**
     * 对 key 所储存的字符串值,获取指定偏移量上的位(bit)
     * @param key
     * @param offset
     * @return
     */
    public static Boolean getBit(String key, long offset) {
        return redisTemplate.opsForValue().getBit(key, offset);
    }

    /**
     * 批量获取
     *
     * @param keys
     * @return
     */
    public static List<String> multiGet(Collection<String> keys) {
        return redisTemplate.opsForValue().multiGet(keys);
    }

    /**
     * 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value
     *
     * @param key   位置
     * @param value 值,true为1, false为0
     * @return
     */
    public static boolean setBit(String key, long offset, boolean value) {
        return redisTemplate.opsForValue().setBit(key, offset, value);
    }

    /**
     * 将值 value 关联到 key ,并将 key 的过期时间设为 timeout
     *
     * @param key
     * @param value
     * @param timeout 过期时间
     * @param unit    时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES
     *                秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
     */
    public static void setEx(String key, String value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 只有在 key 不存在时设置 key 的值
     *
     * @param key
     * @param value
     * @return 之前已经存在返回false, 不存在返回true
     */
    public static boolean setIfAbsent(String key, String value) {
        return redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    /**
     * 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始
     *
     * @param key
     * @param value
     * @param offset 从指定位置开始覆写
     */
    public static void setRange(String key, String value, long offset) {
        redisTemplate.opsForValue().set(key, value, offset);
    }

    /**
     * 获取字符串的长度
     *
     * @param key
     * @return
     */
    public static Long size(String key) {
        return redisTemplate.opsForValue().size(key);
    }

    /**
     * 批量添加
     *
     * @param maps
     */
    public static void multiSet(Map<String, String> maps) {
        redisTemplate.opsForValue().multiSet(maps);
    }

    /**
     * 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
     *
     * @param maps
     * @return 之前已经存在返回false, 不存在返回true
     */
    public static boolean multiSetIfAbsent(Map<String, String> maps) {
        return redisTemplate.opsForValue().multiSetIfAbsent(maps);
    }

    /**
     * 增加(自增长), 负数则为自减
     *
     * @param key
     * @return
     */
    public static Long incrBy(String key, long increment) {
        return redisTemplate.opsForValue().increment(key, increment);
    }

    /**
     * @param key
     * @return
     */
    public static Double incrByFloat(String key, double increment) {
        return redisTemplate.opsForValue().increment(key, increment);
    }

    /**
     * 追加到末尾
     *
     * @param key
     * @param value
     * @return
     */
    public static Integer append(String key, String value) {
        return redisTemplate.opsForValue().append(key, value);
    }
}

RedisHashUtil

java 复制代码
package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisHashUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisHashUtil.redisTemplate = redisTemplate;
    }
    /** -------------------hash相关操作------------------------- */
    /**
     * 获取存储在哈希表中指定字段的值
     *
     * @param key
     * @param field
     * @return
     */
    public static Object hGet(String key, String field) {
        return redisTemplate.opsForHash().get(key, field);
    }

    /**
     * 获取所有给定字段的值
     *
     * @param key
     * @return
     */
    public static Map<Object, Object> hGetAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 获取所有给定字段的值
     *
     * @param key
     * @param fields
     * @return
     */
    public static List<Object> hMultiGet(String key, Collection<Object> fields) {
        return redisTemplate.opsForHash().multiGet(key, fields);
    }

    public static void hPut(String key, String hashKey, String value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    public static void hPutAll(String key, Map<String, String> maps) {
        redisTemplate.opsForHash().putAll(key, maps);
    }

    /**
     * 仅当hashKey不存在时才设置
     *
     * @param key
     * @param hashKey
     * @param value
     * @return
     */
    public static Boolean hPutIfAbsent(String key, String hashKey, String value) {
        return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
    }

    /**
     * 删除一个或多个哈希表字段
     *
     * @param key
     * @param fields
     * @return
     */
    public static Long hDelete(String key, Object... fields) {
        return redisTemplate.opsForHash().delete(key, fields);
    }

    /**
     * 查看哈希表 key 中,指定的字段是否存在
     *
     * @param key
     * @param field
     * @return
     */
    public static boolean hExists(String key, String field) {
        return redisTemplate.opsForHash().hasKey(key, field);
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     *
     * @param key
     * @param field
     * @param increment
     * @return
     */
    public static Long hIncrBy(String key, Object field, long increment) {
        return redisTemplate.opsForHash().increment(key, field, increment);
    }

    /**
     * 为哈希表 key 中的指定字段的整数值加上增量 increment
     *
     * @param key
     * @param field
     * @param delta
     * @return
     */
    public static Double hIncrByFloat(String key, Object field, double delta) {
        return redisTemplate.opsForHash().increment(key, field, delta);
    }

    /**
     * 获取所有哈希表中的字段
     *
     * @param key
     * @return
     */
    public static Set<Object> hKeys(String key) {
        return redisTemplate.opsForHash().keys(key);
    }

    /**
     * 获取哈希表中字段的数量
     *
     * @param key
     * @return
     */
    public static Long hSize(String key) {
        return redisTemplate.opsForHash().size(key);
    }

    /**
     * 获取哈希表中所有值
     *
     * @param key
     * @return
     */
    public static List<Object> hValues(String key) {
        return redisTemplate.opsForHash().values(key);
    }

    /**
     * 迭代哈希表中的键值对
     *
     * @param key
     * @param options
     * @return
     */
    public static Cursor<Map.Entry<Object, Object>> hScan(String key, ScanOptions options) {
        return redisTemplate.opsForHash().scan(key, options);
    }
}

RedisListUtil

java 复制代码
package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

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

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisListUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisListUtil.redisTemplate = redisTemplate;
    }

    /** ------------------------list相关操作---------------------------- */
    /**
     * 通过索引获取列表中的元素
     *
     * @param key
     * @param index
     * @return
     */
    public static String lIndex(String key, long index) {
        return redisTemplate.opsForList().index(key, index);
    }

    /**
     * 获取列表指定范围内的元素
     *
     * @param key
     * @param start 开始位置, 0是开始位置
     * @param end   结束位置, -1返回所有
     * @return
     */
    public static List<String> lRange(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 存储在list头部
     *
     * @param key
     * @param value
     * @return
     */
    public static Long lLeftPush(String key, String value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public static Long lLeftPushAll(String key, String... value) {
        return redisTemplate.opsForList().leftPushAll(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public static Long lLeftPushAll(String key, Collection<String> value) {
        return redisTemplate.opsForList().leftPushAll(key, value);
    }

    /**
     * 当list存在的时候才加入
     *
     * @param key
     * @param value
     * @return
     */
    public static Long lLeftPushIfPresent(String key, String value) {
        return redisTemplate.opsForList().leftPushIfPresent(key, value);
    }

    /**
     * 如果pivot存在,再pivot前面添加
     *
     * @param key
     * @param pivot
     * @param value
     * @return
     */
    public static Long lLeftPush(String key, String pivot, String value) {
        return redisTemplate.opsForList().leftPush(key, pivot, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public static Long lRightPush(String key, String value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public static Long lRightPushAll(String key, String... value) {
        return redisTemplate.opsForList().rightPushAll(key, value);
    }

    /**
     * @param key
     * @param value
     * @return
     */
    public static Long lRightPushAll(String key, Collection<String> value) {
        return redisTemplate.opsForList().rightPushAll(key, value);
    }

    /**
     * 为已存在的列表添加值
     *
     * @param key
     * @param value
     * @return
     */
    public static Long lRightPushIfPresent(String key, String value) {
        return redisTemplate.opsForList().rightPushIfPresent(key, value);
    }

    /**
     * 在pivot元素的右边添加值
     *
     * @param key
     * @param pivot
     * @param value
     * @return
     */
    public static Long lRightPush(String key, String pivot, String value) {
        return redisTemplate.opsForList().rightPush(key, pivot, value);
    }

    /**
     * 通过索引设置列表元素的值
     *
     * @param key
     * @param index 位置
     * @param value
     */
    public static void lSet(String key, long index, String value) {
        redisTemplate.opsForList().set(key, index, value);
    }

    /**
     * 移出并获取列表的第一个元素
     *
     * @param key
     * @return 删除的元素
     */
    public static String lLeftPop(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param key
     * @param timeout 等待时间
     * @param unit    时间单位
     * @return
     */
    public static String lBLeftPop(String key, long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().leftPop(key, timeout, unit);
    }

    /**
     * 移除并获取列表最后一个元素
     *
     * @param key
     * @return 删除的元素
     */
    public static String lRightPop(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param key
     * @param timeout 等待时间
     * @param unit    时间单位
     * @return
     */
    public static String lBRightPop(String key, long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().rightPop(key, timeout, unit);
    }

    /**
     * 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
     *
     * @param sourceKey
     * @param destinationKey
     * @return
     */
    public static String lRightPopAndLeftPush(String sourceKey, String destinationKey) {
        return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,
                destinationKey);
    }

    /**
     * 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
     *
     * @param sourceKey
     * @param destinationKey
     * @param timeout
     * @param unit
     * @return
     */
    public static String lBRightPopAndLeftPush(String sourceKey, String destinationKey,
                                               long timeout, TimeUnit unit) {
        return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,
                destinationKey, timeout, unit);
    }

    /**
     * 删除集合中值等于value得元素
     *
     * @param key
     * @param index index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素;
     *              index<0, 从尾部开始删除第一个值等于value的元素;
     * @param value
     * @return
     */
    public static Long lRemove(String key, long index, String value) {
        return redisTemplate.opsForList().remove(key, index, value);
    }

    /**
     * 裁剪list
     *
     * @param key
     * @param start
     * @param end
     */
    public static void lTrim(String key, long start, long end) {
        redisTemplate.opsForList().trim(key, start, end);
    }

    /**
     * 获取列表长度
     *
     * @param key
     * @return
     */
    public static Long lLen(String key) {
        return redisTemplate.opsForList().size(key);
    }
}

RedisSetUtil

java 复制代码
package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisSetUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisSetUtil.redisTemplate = redisTemplate;
    }
    /** --------------------set相关操作-------------------------- */
    /**
     * set添加元素
     *
     * @param key
     * @param values
     * @return
     */
    public static Long sAdd(String key, String... values) {
        return redisTemplate.opsForSet().add(key, values);
    }

    /**
     * set移除元素
     *
     * @param key
     * @param values
     * @return
     */
    public static Long sRemove(String key, Object... values) {
        return redisTemplate.opsForSet().remove(key, values);
    }

    /**
     * 移除并返回集合的一个随机元素
     *
     * @param key
     * @return
     */
    public static String sPop(String key) {
        return redisTemplate.opsForSet().pop(key);
    }

    /**
     * 将元素value从一个集合移到另一个集合
     *
     * @param key
     * @param value
     * @param destKey
     * @return
     */
    public static Boolean sMove(String key, String value, String destKey) {
        return redisTemplate.opsForSet().move(key, value, destKey);
    }

    /**
     * 获取集合的大小
     *
     * @param key
     * @return
     */
    public static Long sSize(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * 判断集合是否包含value
     *
     * @param key
     * @param value
     * @return
     */
    public static Boolean sIsMember(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    /**
     * 获取两个集合的交集
     *
     * @param key
     * @param otherKey
     * @return
     */
    public static Set<String> sIntersect(String key, String otherKey) {
        return redisTemplate.opsForSet().intersect(key, otherKey);
    }

    /**
     * 获取key集合与多个集合的交集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public static Set<String> sIntersect(String key, Collection<String> otherKeys) {
        return redisTemplate.opsForSet().intersect(key, otherKeys);
    }

    /**
     * key集合与otherKey集合的交集存储到destKey集合中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public static Long sIntersectAndStore(String key, String otherKey, String destKey) {
        return redisTemplate.opsForSet().intersectAndStore(key, otherKey,
                destKey);
    }

    /**
     * key集合与多个集合的交集存储到destKey集合中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public static Long sIntersectAndStore(String key, Collection<String> otherKeys,
                                          String destKey) {
        return redisTemplate.opsForSet().intersectAndStore(key, otherKeys,
                destKey);
    }

    /**
     * 获取两个集合的并集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public static Set<String> sUnion(String key, String otherKeys) {
        return redisTemplate.opsForSet().union(key, otherKeys);
    }

    /**
     * 获取key集合与多个集合的并集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public static Set<String> sUnion(String key, Collection<String> otherKeys) {
        return redisTemplate.opsForSet().union(key, otherKeys);
    }

    /**
     * key集合与otherKey集合的并集存储到destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public static Long sUnionAndStore(String key, String otherKey, String destKey) {
        return redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey);
    }

    /**
     * key集合与多个集合的并集存储到destKey中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public static Long sUnionAndStore(String key, Collection<String> otherKeys,
                                      String destKey) {
        return redisTemplate.opsForSet().unionAndStore(key, otherKeys, destKey);
    }

    /**
     * 获取两个集合的差集
     *
     * @param key
     * @param otherKey
     * @return
     */
    public static Set<String> sDifference(String key, String otherKey) {
        return redisTemplate.opsForSet().difference(key, otherKey);
    }

    /**
     * 获取key集合与多个集合的差集
     *
     * @param key
     * @param otherKeys
     * @return
     */
    public static Set<String> sDifference(String key, Collection<String> otherKeys) {
        return redisTemplate.opsForSet().difference(key, otherKeys);
    }

    /**
     * key集合与otherKey集合的差集存储到destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public static Long sDifference(String key, String otherKey, String destKey) {
        return redisTemplate.opsForSet().differenceAndStore(key, otherKey,
                destKey);
    }

    /**
     * key集合与多个集合的差集存储到destKey中
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public static Long sDifference(String key, Collection<String> otherKeys,
                                   String destKey) {
        return redisTemplate.opsForSet().differenceAndStore(key, otherKeys,
                destKey);
    }

    /**
     * 获取集合所有元素
     *
     * @param key
     * @return
     */
    public static Set<String> setMembers(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 随机获取集合中的一个元素
     *
     * @param key
     * @return
     */
    public static String sRandomMember(String key) {
        return redisTemplate.opsForSet().randomMember(key);
    }

    /**
     * 随机获取集合中count个元素
     *
     * @param key
     * @param count
     * @return
     */
    public static List<String> sRandomMembers(String key, long count) {
        return redisTemplate.opsForSet().randomMembers(key, count);
    }

    /**
     * 随机获取集合中count个元素并且去除重复的
     *
     * @param key
     * @param count
     * @return
     */
    public static Set<String> sDistinctRandomMembers(String key, long count) {
        return redisTemplate.opsForSet().distinctRandomMembers(key, count);
    }

    /**
     * @param key
     * @param options
     * @return
     */
    public static Cursor<String> sScan(String key, ScanOptions options) {
        return redisTemplate.opsForSet().scan(key, options);
    }
}

RedisZsetUtil

java 复制代码
package cn.smbms.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Set;

/**
 * @author: zjl
 * @datetime: 2024/4/26
 * @desc:
 */
@Component
public class RedisZsetUtil {
    private static StringRedisTemplate redisTemplate;
    @Autowired
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        RedisZsetUtil.redisTemplate = redisTemplate;
    }

    /**------------------zSet相关操作--------------------------------*/
    /**
     * 添加元素,有序集合是按照元素的score值由小到大排列
     *
     * @param key
     * @param value
     * @param score
     * @return
     */
    public static Boolean zAdd(String key, String value, double score) {
        return redisTemplate.opsForZSet().add(key, value, score);
    }

    /**
     * @param key
     * @param values
     * @return
     */
    public static Long zAdd(String key, Set<ZSetOperations.TypedTuple<String>> values) {
        return redisTemplate.opsForZSet().add(key, values);
    }

    /**
     * @param key
     * @param values
     * @return
     */
    public static Long zRemove(String key, Object... values) {
        return redisTemplate.opsForZSet().remove(key, values);
    }

    /**
     * 增加元素的score值,并返回增加后的值
     *
     * @param key
     * @param value
     * @param delta
     * @return
     */
    public static Double zIncrementScore(String key, String value, double delta) {
        return redisTemplate.opsForZSet().incrementScore(key, value, delta);
    }

    /**
     * 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
     *
     * @param key
     * @param value
     * @return 0表示第一位
     */
    public static Long zRank(String key, Object value) {
        return redisTemplate.opsForZSet().rank(key, value);
    }

    /**
     * 返回元素在集合的排名,按元素的score值由大到小排列
     *
     * @param key
     * @param value
     * @return
     */
    public static Long zReverseRank(String key, Object value) {
        return redisTemplate.opsForZSet().reverseRank(key, value);
    }

    /**
     * 获取集合的元素, 从小到大排序
     *
     * @param key
     * @param start 开始位置
     * @param end   结束位置, -1查询所有
     * @return
     */
    public static Set<String> zRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }

    /**
     * 获取集合元素, 并且把score值也获取
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static Set<ZSetOperations.TypedTuple<String>> zRangeWithScores(String key, long start,
                                                                          long end) {
        return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
    }

    /**
     * 根据Score值查询集合元素
     *
     * @param key
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public static Set<String> zRangeByScore(String key, double min, double max) {
        return redisTemplate.opsForZSet().rangeByScore(key, min, max);
    }

    /**
     * 根据Score值查询集合元素, 从小到大排序
     *
     * @param key
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public static Set<ZSetOperations.TypedTuple<String>> zRangeByScoreWithScores(String key,
                                                                                 double min, double max) {
        return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
    }

    /**
     * @param key
     * @param min
     * @param max
     * @param start
     * @param end
     * @return
     */
    public static Set<ZSetOperations.TypedTuple<String>> zRangeByScoreWithScores(String key,
                                                                                 double min, double max, long start, long end) {
        return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max,
                start, end);
    }

    /**
     * 获取集合的元素, 从大到小排序
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static Set<String> zReverseRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().reverseRange(key, start, end);
    }

    /**
     * 获取集合的元素, 从大到小排序, 并返回score值
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static Set<ZSetOperations.TypedTuple<String>> zReverseRangeWithScores(String key,
                                                                                 long start, long end) {
        return redisTemplate.opsForZSet().reverseRangeWithScores(key, start,
                end);
    }

    /**
     * 根据Score值查询集合元素, 从大到小排序
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public static Set<String> zReverseRangeByScore(String key, double min,
                                                   double max) {
        return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
    }

    /**
     * 根据Score值查询集合元素, 从大到小排序
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public static Set<ZSetOperations.TypedTuple<String>> zReverseRangeByScoreWithScores(
            String key, double min, double max) {
        return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key,
                min, max);
    }

    /**
     * @param key
     * @param min
     * @param max
     * @param start
     * @param end
     * @return
     */
    public static Set<String> zReverseRangeByScore(String key, double min,
                                                   double max, long start, long end) {
        return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max,
                start, end);
    }

    /**
     * 根据score值获取集合元素数量
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public static Long zCount(String key, double min, double max) {
        return redisTemplate.opsForZSet().count(key, min, max);
    }

    /**
     * 获取集合大小
     *
     * @param key
     * @return
     */
    public static Long zSize(String key) {
        return redisTemplate.opsForZSet().size(key);
    }

    /**
     * 获取集合大小
     *
     * @param key
     * @return
     */
    public static Long zZCard(String key) {
        return redisTemplate.opsForZSet().zCard(key);
    }

    /**
     * 获取集合中value元素的score值
     *
     * @param key
     * @param value
     * @return
     */
    public static Double zScore(String key, Object value) {
        return redisTemplate.opsForZSet().score(key, value);
    }

    /**
     * 移除指定索引位置的成员
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static Long zRemoveRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().removeRange(key, start, end);
    }

    /**
     * 根据指定的score值的范围来移除成员
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public static Long zRemoveRangeByScore(String key, double min, double max) {
        return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
    }

    /**
     * 获取key和otherKey的并集并存储在destKey中
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public static Long zUnionAndStore(String key, String otherKey, String destKey) {
        return redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey);
    }

    /**
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public static Long zUnionAndStore(String key, Collection<String> otherKeys,
                                      String destKey) {
        return redisTemplate.opsForZSet()
                .unionAndStore(key, otherKeys, destKey);
    }

    /**
     * 交集
     *
     * @param key
     * @param otherKey
     * @param destKey
     * @return
     */
    public static Long zIntersectAndStore(String key, String otherKey,
                                          String destKey) {
        return redisTemplate.opsForZSet().intersectAndStore(key, otherKey,
                destKey);
    }

    /**
     * 交集
     *
     * @param key
     * @param otherKeys
     * @param destKey
     * @return
     */
    public static Long zIntersectAndStore(String key, Collection<String> otherKeys,
                                          String destKey) {
        return redisTemplate.opsForZSet().intersectAndStore(key, otherKeys,
                destKey);
    }

    /**
     * @param key
     * @param options
     * @return
     */
    public static Cursor<ZSetOperations.TypedTuple<String>> zScan(String key, ScanOptions options) {
        return redisTemplate.opsForZSet().scan(key, options);
    }
}

备注

为了方便操作,也可以把这几个类合并到一个RedisUtil类中

6.测试

随便写几个测试用例了

通用

java 复制代码
    @Test
    void redisKey() {
        Set<String> keys = RedisKeyUtil.keys("*");
        keys.forEach(key -> {
            log.info("key:{}",key);
        });
        RedisKeyUtil.delete("userName");
        RedisKeyUtil.delete(keys);
        boolean isExist = RedisKeyUtil.hasKey("userName");
        boolean at = RedisKeyUtil.expire("userName", 10, TimeUnit.SECONDS);
        long expire = RedisKeyUtil.getExpire("userName");
    }

string

java 复制代码
    @Test
    void redisStringUtil() {
        RedisStringUtil.set("userName", "系统管理员");
        log.info("写入userName到Redis中完毕");
        String userName = RedisStringUtil.get("userName");
        log.info("从Redis中取出userName的值是:{}",userName);
    }

Redis的注解式开发

  • 1.注意:一般开发中小型快速应用,适合redis注解开发。但是想要合理点的设置缓存,建议还是手动配置
  • 2.被缓存的实体类记得实现Serializable接口

启动类添加开启缓存注解

java 复制代码
@SpringBootApplication
@EnableCaching
public class RedisdemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisdemoApplication.class, args);
    }
}

常用注解

@Cacheable注解

解释:
  • 先从redis数据库中按照当前key查找,有没有;
  • 如果redis中有,是不会走当前该方法的;
  • 如果没有再调用方法返回结果,如果结果不为null将其缓存到数据库中(一般用于find)
属性
  • value:key的一部分(前缀),主要是指明数据放在那个key范围
  • key:key的主体,#p0:指明取出第一个参数 #p1:指明取出第二个参数。。。依此类推;或者#参数名
  • unless:结果为true,将当前的数据结果不保存到redis,#result:指明取出数据库中返回的结果
  • condition 结果如果为true,将当前数据保存到redis
示例

mapper层

java 复制代码
@Mapper//图省事,在这里加上@Mapper注解,否则在启动类上加@MapperScan("cn.smbms.mapper")
public interface UserMapper {
    @Select("select * from smbms_user where id=#{id}")
    User selectUserById(int id);
}

service层添加缓存注解

java 复制代码
@Service
public class UserService {
    @Resource
    private UserMapper userMapper;
    @Cacheable(value = "user",key = "#id",unless = "#result == null",condition = "#id > 1")
    public User getUserDetail(int id){
        return userMapper.selectUserById(id);
    }
}

测试

java 复制代码
    @Test
    public void select(){
        System.out.println(userService.getUserDetail(1));//不会添加到缓存
        System.out.println(userService.getUserDetail(99));//结果为空,不会加入到缓存
        System.out.println(userService.getUserDetail(7));//会添加到缓存
    }

当再次查询ID为7的数据时,就会从redis中获取,而不会再查询数据库了

测试

java 复制代码
    @Test
    public void select(){
        //System.out.println(userService.getUserDetail(1));//不会添加到缓存
        //System.out.println(userService.getUserDetail(99));//结果为空,不会加入到缓存
        System.out.println(userService.getUserDetail(7));//会添加到缓存
    }

返回结果:没有SQL记录

java 复制代码
2024-04-26 14:10:37.030  INFO 23524 --- [           main] cn.smbms.RedisdemoApplicationTests       : Started RedisdemoApplicationTests in 5.091 seconds (JVM running for 6.098)
User(id=7, userCode=wangyang, userName=王洋, userPassword=1, gender=2, birthday=Fri Dec 31 00:00:00 CST 1982, phone=13444561124, address=北京市海淀区西二旗辉煌国际16层, userRole=3, createdBy=1, creationDate=Wed Jun 11 19:09:07 CST 2014, modifyBy=null, modifyDate=null)
2024-04-26 14:10:38.167  INFO 23524 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

@CachePut注解

解释
  • 主要用于向数据库中插入数据,向数据中插入数据的时候,会将返回的int类型,放入redis中缓存,当然是有选择性的(一般用于insert)
属性
  • value:key的一部分,命名空间
  • key:指定key的名称
  • unless:满足条件,则不将返回的结果放入redis
  • condition: 满足条件,则将返回的结果放入redis
示例

mapper层

java 复制代码
    @Insert("insert into smbms_user(userCode,userName,phone,address,userRole) values(#{userCode},#{userName},#{phone},#{address},#{userRole})")
    @Options(useGeneratedKeys = true, keyProperty = "id")//返回自增主键
    int insertUser(User user);

service层

java 复制代码
    @CachePut(value = "user",key = "#user.id",unless = "#result == null",condition = "#user.userRole == 3")
    public User saveUser(User user){
        userMapper.insertUser(user);
        return user;
    }

测试

java 复制代码
    @Test
    public void save(){
        System.out.println(userService.saveUser(new User("aaa","AAA","180","郑州",2)));//userRole!=3,不会缓存
        System.out.println(userService.saveUser(new User("bbb","BBB","138","南京",3)));//userRole==3,会缓存
    }
注意

修改也是同样的操作

@CacheEvict注解

解释

满足条件则移除当前key在redis中的数据(一般用于update/delete)

属性
  • value: 同理命名空间
  • key: key名称
  • condition:满足什么条件从缓存中移除指定的key
  • AllEntries:true/false 是否移除命名空间下的所有key
示例

mapper层

java 复制代码
    @Delete("delete from smbms_user where id=#{id}")
    int deleteUserById(int id);

service层

java 复制代码
    @CacheEvict(value = "user",key = "#id",allEntries = true)
    public boolean deleteUser(int id){
        return userMapper.deleteUserById(id) > 0;
    }

测试

java 复制代码
    @Test
    public void delete(){
        System.out.println(userService.deleteUser(82));
    }

此时会把user这个命名空间下所有的数据都删除,因为allEntries = true

重新添加几条数据
service层的删除方法去掉allEntries = true,或者设置为false,再次测试

java 复制代码
    @Test
    public void delete(){
        System.out.println(userService.deleteUser(84));
    }

思考

  • 我们知道如果进行查询的时候,会将数据缓存到redis中。
  • 一旦进行增删改,那么原本数据库中的数据可能会发生变化,那么增删改成功后,应该要指定的移除指定key的缓存。
  • 但是我们通过@CaheEvict移除指定key的数据,发现并不能行的通。
解决方案1:
  • @CaheEvict(value="nameSpace",allEntries=true),移除这个命名空间下的所有数据
解决方案2:
  • 通过redisTemplate手动移除相关联的key的数据(相对来说麻烦点)

@CacheConfig注解

解释
  • 所有的@Cacheable()里面都有一个value="xxx"的属性,这显然如果方法多了,写起来也是挺累的
  • 如果可以一次性声明完 那就省事了, 所以,有了@CacheConfig这个配置,一个类中可能会有多个缓存操作,而这些缓存操作可能是重复的。这个时候可以使用@CacheConfig。
java 复制代码
    @Cacheable(key = "#id",unless = "#result == null",condition = "#id > 1")
    public User getUserDetail(int id){
        return userMapper.selectUserById(id);
    }

@Caching注解

解释
  • 有时候我们可能组合多个Cache注解使用;
  • 比如用户新增成功后,我们要添加id-->user;username--->user;email--->user的缓存;
  • 此时就需要@Caching组合多个注解标签了。
java 复制代码
    @Caching(put = {
	    @CachePut(value = "user", key = "#user.id"),
	    @CachePut(value = "user", key = "#user.userCode"),
	    @CachePut(value = "user", key = "#user.phone")
    })
    public User save(User user) {
     ...
    }
相关推荐
科技资讯早知道2 分钟前
java计算机毕设课设—坦克大战游戏
java·开发语言·游戏·毕业设计·课程设计·毕设
全栈师7 分钟前
SQL Server中关于个性化需求批量删除表的做法
数据库·oracle
Data 31715 分钟前
Hive数仓操作(十七)
大数据·数据库·数据仓库·hive·hadoop
苹果醋341 分钟前
快速玩转 Mixtral 8x7B MOE大模型!阿里云机器学习 PAI 推出最佳实践
spring boot·nginx·毕业设计·layui·课程设计
BergerLee44 分钟前
对不经常变动的数据集合添加Redis缓存
数据库·redis·缓存
程序员大金1 小时前
基于SpringBoot+Vue+MySQL的装修公司管理系统
vue.js·spring boot·mysql
小比卡丘1 小时前
C语言进阶版第17课—自定义类型:联合和枚举
android·java·c语言
gorgor在码农1 小时前
Mysql 索引底层数据结构和算法
数据结构·数据库·mysql
xmh-sxh-13141 小时前
java 数据存储方式
java
Dylanioucn1 小时前
【分布式微服务云原生】掌握分布式缓存:Redis与Memcached的深入解析与实战指南
分布式·缓存·云原生