Redis工具类
文章目录
- Redis的自动配置
- Redis配置类
- 问题 一
- 问题二
- Redis工具类
Redis的自动配置
通过源码可以看出,SpringBoot自动帮我们在容器中生成了一个RedisTemplate和一个StringRedisTemplate。
看到这个**@ConditionalOnMissingBean注解后,就知道如果Spring容器中有了RedisTemplate对象了,这个自动配置的RedisTemplate不会实例化**。因此我们可以直接自己写个配置类,配置RedisTemplate。
该注解核心作用是:当容器中不存在指定类型(或名称)的 Bean 时,才会创建当前注解标注的 Bean。
Redis配置类
代码如下:
@Configuration
public class RedisConfig {@Bean@SuppressWarnings(value = { "unchecked", "rawtypes" })public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;}
}
问题 一
@SuppressWarnings(value = { "unchecked", "rawtypes" })
的作用
这个注解用于抑制编译器产生的未检查类型转换警告(unchecked
)和原始类型使用警告(rawtypes
)。
unchecked
警告
当代码中存在没有进行类型检查的泛型转换时,编译器会提示警告。例如:
List<String> list = (List<String>) redisTemplate.opsForValue().get("key");
这里的强制类型转换没有进行运行时检查,可能在运行时抛出ClassCastException
。添加@SuppressWarnings("unchecked")
可以消除这个警告。
rawtypes
警告
当使用泛型类但没有指定具体类型参数时,编译器会提示原始类型警告。
RedisTemplate template = new RedisTemplate(); // 未指定泛型参数
问题二
此配置类作用?
为什么需要配置序列化器?
- 序列化方式不符合预期,出现乱码或不可读数据
RedisTemplate 默认的序列化器如下:
- key 和 value 的默认序列化器:
JdkSerializationRedisSerializer
(基于 JDK 自带的序列化) - Hash 结构的 key 和 value 默认序列化器:同样是
JdkSerializationRedisSerializer
这种默认序列化会导致:
- 存储到 Redis 中的 key 和 value 会带有额外的类信息(如
\xAC\xED\x00\x05t\x00\x06test
),在 Redis 客户端(如 Redis Desktop Manager)中查看时是乱码,无法直观阅读。 - 反序列化时依赖类的全路径名,如果类名或包名修改,会导致反序列化失败(报
ClassNotFoundException
)。
- 自定义对象存储失败
如果直接使用未配置的 RedisTemplate 存储自定义实体类对象,会因为默认序列化器的限制:
- 要求对象必须实现
Serializable
接口,否则抛出序列化异常。 - 即使实现了
Serializable
,也会如上述问题一样,存储的数据可读性差,且耦合性高(依赖类结构)
配置前:
配置后:
- key 和 hashKey 用 StringRedisSerializer 的必要性
- Redis 的 key 通常是字符串(如
user:100
、order:200
),StringRedisSerializer
能确保 key 以可读的字符串形式存储,避免序列化后出现乱码(如 JDK 序列化会导致 key 带类名前缀)。 - hashKey 是 Redis Hash 结构中的字段名,同样需要可读性,因此也采用
StringRedisSerializer
。
- Redis 的 key 通常是字符串(如
- value 和 hashValue 用 FastJsonRedisSerializer 的合理性
- 示例选择 FastJson 作为 value 序列化器,是因为 JSON 格式具有 可读性强、体积小 的优点,且 FastJson 性能较高。
- 对于 Java 对象(如实体类、集合),JSON 序列化能兼容大多数场景,避免 JDK 序列化的缺点(如必须实现
Serializable
接口、数据不可读)。
- 无需配置其他序列化器的原因
- RedisTemplate 的序列化器配置遵循 “全局默认” 原则:一旦通过
setKeySerializer
、setValueSerializer
等方法设置了序列化器,所有通过该 RedisTemplate 操作 Redis 的请求都会使用这些序列化器。 - 示例场景中,
StringRedisSerializer
(key)+FastJsonRedisSerializer
(value)已覆盖绝大多数常见需求(字符串 key + JSON 对象 value),因此无需额外配置其他序列化器。
- RedisTemplate 的序列化器配置遵循 “全局默认” 原则:一旦通过
Redis工具类
这里的工具类并不是完整的,但学习够用了。
package com.luxiya.utils;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;import java.util.*;
import java.util.concurrent.TimeUnit;@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache
{@Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值*/public <T> void setCacheObject(final String key, final T value){redisTemplate.opsForValue().set(key, value);}/*** 缓存基本的对象,Integer、String、实体类等** @param key 缓存的键值* @param value 缓存的值* @param timeout 时间* @param timeUnit 时间颗粒度*/public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit){redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout){return expire(key, timeout, TimeUnit.SECONDS);}/*** 设置有效时间** @param key Redis键* @param timeout 超时时间* @param unit 时间单位* @return true=设置成功;false=设置失败*/public boolean expire(final String key, final long timeout, final TimeUnit unit){return redisTemplate.expire(key, timeout, unit);}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T getCacheObject(final String key){ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 删除单个对象** @param key*/public boolean deleteObject(final String key){return redisTemplate.delete(key);}/*** 删除集合对象** @param collection 多个对象* @return*/public long deleteObject(final Collection collection){return redisTemplate.delete(collection);}/*** 缓存List数据** @param key 缓存的键值* @param dataList 待缓存的List数据* @return 缓存的对象*/public <T> long setCacheList(final String key, final List<T> dataList){Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}/*** 获得缓存的list对象** @param key 缓存的键值* @return 缓存键值对应的数据*/public <T> List<T> getCacheList(final String key){return redisTemplate.opsForList().range(key, 0, -1);}/*** 缓存Set** @param key 缓存键值* @param dataSet 缓存的数据* @return 缓存数据的对象*/public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet){BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);Iterator<T> it = dataSet.iterator();while (it.hasNext()){setOperation.add(it.next());}return setOperation;}/*** 获得缓存的set** @param key* @return*/public <T> Set<T> getCacheSet(final String key){return redisTemplate.opsForSet().members(key);}/*** 缓存Map** @param key* @param dataMap*/public <T> void setCacheMap(final String key, final Map<String, T> dataMap){if (dataMap != null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 获得缓存的Map** @param key* @return*/public <T> Map<String, T> getCacheMap(final String key){return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入数据** @param key Redis键* @param hKey Hash键* @param value 值*/public <T> void setCacheMapValue(final String key, final String hKey, final T value){redisTemplate.opsForHash().put(key, hKey, value);}/*** 获取Hash中的数据** @param key Redis键* @param hKey Hash键* @return Hash中的对象*/public <T> T getCacheMapValue(final String key, final String hKey){HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/*** 删除Hash中的数据** @param key* @param hkey*/public void delCacheMapValue(final String key, final String hkey){HashOperations hashOperations = redisTemplate.opsForHash();hashOperations.delete(key, hkey);}/*** 获取多个Hash中的数据** @param key Redis键* @param hKeys Hash键集合* @return Hash对象集合*/public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys){return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 获得缓存的基本对象列表** @param pattern 字符串前缀* @return 对象列表*/public Collection<String> keys(final String pattern){return redisTemplate.keys(pattern);}
}