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

目录

  • SpringBoot整合Redis
    • 1.下载和安装Redis
    • 2.新建工程,导入依赖
    • 3.添加配置
    • 4.先来几个基本的示例
      • 测试代码
      • 输出结果
      • 用redis客户端查看一下存储内容
    • 5.封装redis工具类
      • RedisKeyUtil
      • RedisStringUtil
      • RedisHashUtil
      • RedisListUtil
      • RedisSetUtil
      • RedisZsetUtil
      • 备注
    • 6.测试
      • 通用
      • string
  • Redis的注解式开发
    • 启动类添加开启缓存注解
    • 常用注解
      • @Cacheable注解
        • 解释:
        • 属性
        • 示例
      • @CachePut注解
        • 解释
        • 属性
        • 示例
        • 注意
      • @CacheEvict注解
        • 解释
        • 属性
        • 示例
      • 思考
        • 解决方案1:
        • 解决方案2:
      • @CacheConfig注解
        • 解释
      • @Caching注解
        • 解释

SpringBoot整合Redis

1.下载和安装Redis

略,可以看我之前的博客

2.新建工程,导入依赖

其中主要是redis依赖

		<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.先来几个基本的示例

测试代码

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 {@Resourceprivate RedisTemplate<Object, Object> redisTemplate;@Resourceprivate StringRedisTemplate stringRedisTemplate;@Testvoid 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);}
}

输出结果

......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

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;@Autowiredpublic 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

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;@Autowiredpublic 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

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;@Autowiredpublic 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

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;@Autowiredpublic 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

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;@Autowiredpublic 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

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;@Autowiredpublic 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.测试

随便写几个测试用例了

通用

    @Testvoid 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

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

Redis的注解式开发

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

启动类添加开启缓存注解

@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层

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

service层添加缓存注解

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

测试

    @Testpublic void select(){System.out.println(userService.getUserDetail(1));//不会添加到缓存System.out.println(userService.getUserDetail(99));//结果为空,不会加入到缓存System.out.println(userService.getUserDetail(7));//会添加到缓存}

在这里插入图片描述
当再次查询ID为7的数据时,就会从redis中获取,而不会再查询数据库了
测试

    @Testpublic void select(){//System.out.println(userService.getUserDetail(1));//不会添加到缓存//System.out.println(userService.getUserDetail(99));//结果为空,不会加入到缓存System.out.println(userService.getUserDetail(7));//会添加到缓存}

返回结果:没有SQL记录

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层

    @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层

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

测试

    @Testpublic 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层

    @Delete("delete from smbms_user where id=#{id}")int deleteUserById(int id);

service层

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

测试

    @Testpublic void delete(){System.out.println(userService.deleteUser(82));}

此时会把user这个命名空间下所有的数据都删除,因为allEntries = true
在这里插入图片描述
重新添加几条数据
在这里插入图片描述service层的删除方法去掉allEntries = true,或者设置为false,再次测试

    @Testpublic 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。
    @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组合多个注解标签了。
    @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) {...}

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

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

相关文章

node.js 解析post请求 方法二

前提&#xff1a;以前面发的node.js解析post请求方法一为模板&#xff0c;具体见 http://t.csdnimg.cn/ABaIn 此文我们运用第二种方法&#xff1a;使用第三方模块formidable对post请求进行解析。 1》代码难点 *** 在Node.js中使用formidable模块来解析POST请求主要涉及到处理…

IO流基础

IO流介绍 1.什么是IO流&#xff1f; 流是一种抽象概念&#xff0c;它代表了数据的无结构化传递。按照流的方式进行输入输出&#xff0c;数据被当成无结构的字节序列或字符序列。从流中取得数据的操作称为提取操作&#xff0c;而向流中添加数据的操作称为插入操作。用来进行输入…

JVM (Micrometer)监控SpringBoot(AWS EKS版)

问题 怎样使用JVM (Micrometer)面板&#xff0c;监控Spring&#xff1f;这里不涉及Prometheus和Grafana&#xff0c;重点介绍与Micrometer与Springboot&#xff0c;k8s怎样集成。 pom.xml 引入依赖&#xff0c;如下&#xff1a; <properties><micrometer.version&…

免费简单好用的内网穿透工具(ngrok、natapp),微信回调地址配置

B站视频地址 文章目录 Natapp1、登录注册账号、下载软件2、使用2-1、购买隧道、查看token2-2、端口穿透 Ngrok1、登录注册账号、下载软件2、使用2-1、获取并设置 token2-2、使用 3、隧道 微信回调配置1、注册测试公众号2、回调代码3、回调配置 在一些特殊的场景下&#xff0c;需…

多种方法求1+12+123+1234……

有网友出了一道题&#xff1a; 从键盘输入一个小于10的正整数n&#xff0c;计算1121231234……&#xff0c;即前n项之和。 第一眼看到题目&#xff0c;直觉告诉我必须使用嵌套的两个for循环&#xff0c;里面的循环生成每一项&#xff0c;外面的循环求和。错误的方向和思路让我…

基于RBF-PID控制器的风力发电系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于RBF-PID控制器的风力发电系统simulink建模与仿真,对比PID控制器和RBF-PID控制器的控制结果。 2.系统仿真结果 3.核心程序与模型 版本&#xff1a;MATLAB2022a 0050 4.系…

Unity进阶之ScriptableObject

目录 ScriptableObject 概述ScriptableObject数据文件的创建数据文件的使用非持久数据让其真正意义上的持久ScriptableObject的应用配置数据复用数据数据带来的多态行为单例模式化的获取数据 ScriptableObject 概述 ScriptableObject是什么 ScriptableObject是Unity提供的一个…

有没有电脑桌面监控软件|十大电脑屏幕监控软件超全盘点!

电脑桌面监控软件已经成为许多领域不可或缺的工具。 无论是企业为了保障数据安全和提高工作效率&#xff0c;还是家长为了监督孩子的学习&#xff0c;甚至是个人为了记录电脑使用行为&#xff0c;都需要这类软件的支持。 本文将对市面上十大电脑屏幕监控软件进行超全盘点&…

智能文案生成器,文案生成改写很强大

在当今数字化时代&#xff0c;随着人工智能的迅猛发展&#xff0c;智能文案生成器正逐渐成为营销和创作领域的一大利器。这些智能工具不仅能够快速生成文案&#xff0c;还能够进行文案改写&#xff0c;使得文案生成的过程更加高效、便捷。正是在这样的背景下&#xff0c;智能文…

CAT:contig稳健物种分类

安装 mamba create -n CAT python3.10 diamond prodigal cd SoftWare git clone https://github.com/MGXlab/CAT_pack chmod 755 给权限 自己构建数据库 names.dmp nodes.dmp文件可以在Kraken2的文件里面找到 Kraken2Bracken&#xff1a;宏基因组物种注释_kracken2配合bracke…

MySQL之binlog归档日志

binlog&#xff08;二进制归档日志&#xff09; binlog 二进制日志记录保存所有执行过的修改操作语句&#xff0c;不保存查询操作。如果 MySQL 服务意外停止&#xff0c;可通过二进制日志文件排查&#xff0c;用户操作或表结构操作&#xff0c;从而来恢复数据库数据。启动 bin…

Java 线程的几种状态

一、 线程的状态 状态是针对当前的线程调度的情况来描述的。因为线程是调度的基本单位&#xff0c;所以状态更应该是线程的属性。在Java中线程的状态一共有六种&#xff1a; 1. 初始(NEW)&#xff1a;新创建了一个线程对象&#xff0c;但还没有调用start()方法。 2. 运行(RUNN…

动静态库以及动态链接

文章目录 静态库制作静态库如何使用静态库 动态库动态库的制作动态库的使用动态链接 库是给别人用的&#xff0c;所以库中一定不存在main函数。库一般会有lib前缀和后缀&#xff0c;去掉前缀和后缀才是库名。 静态库 静态库&#xff08;.a&#xff09;&#xff1a;程序在编译…

C++|对象与const

目录 常对象 常对象的声明 性质 数据成员不能被修改 常对象不能调用非const成员函数 const型成员函数 常对象成员 常数据成员 常成员函数 注意 总结 const型数据成员 const型成员函数 常对象 指针与const 指向对象的常指针 应用场景 指向常对象的指针 指向常…

Swagger3.0(Springdoc)日常使用记录

文章目录 前言一、默认地址二、注解OperationTag 三、SpringBoot基础配置四、Swagger导入apifox五、Swagger其他配置六 knife4j 参考文章 前言 本文并不是Swagger的使用教程&#xff0c;只是记录一下本人的操作&#xff0c;感兴趣的可以看下 一、默认地址 http://localhost:…

【1731】jsp 房租跟踪监控管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 房租跟踪监控管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysq…

Java 基础常见面试题整理

目录 1、java的基本数据类型有哪些&#xff1f;2、java为什么要有包装类型&#xff1f;3、String a "123" 和 String a new String("123") 区别&#xff1f;4、String、StringBuilder和StringBuffer的区别&#xff1f;5、如何理解面向对象和面向过程&…

浅谈叉车车载电脑的市场现状

叉车的起源 叉车源于美国&#xff0c;兴于日本&#xff0c;虽然中国起步较晚&#xff0c;但是近些年来发展迅速。叉车又称叉式装载车&#xff0c;是对于成件托盘类货物进行装卸、堆垛和短距离运输&#xff0c;实现重物搬运作业的轮式工业车辆。 叉车的分类 叉车分为以上六大类…

CSS学习(选择器、盒子模型)

1、CSS了解 CSS&#xff1a;层叠样式表&#xff0c;一种标记语言&#xff0c;用于给HTML结构设置样式。 样式&#xff1a;文字大小、背景颜色等 p标签内不能嵌套标题标签。 px是相对于分辨率而言的&#xff0c; em是相对于浏览器的默认字体&#xff0c; rem是相对于HTML根元…

刷题日记 ---- 顺序表与链表相关经典算法题(C语言版)

目录 1. 移除元素2. 合并两个有序数组3. 移除链表元素4. 反转链表5. 合并两个有序链表6. 链表的中间结点7. 环形链表的约瑟夫问题8. 分割链表总结 正文开始 1. 移除元素 题目链接: 移除元素 题目描述: 思路历程: 题目明确要求, 不能使用额外的数组空间, 也就是说不可以创建…