共计 13867 个字符,预计需要花费 35 分钟才能阅读完成。
看了好多篇文章,再根据自己的理解进行的配置。
一、Mevan 相关配置
1. 我的 SpringBoot 版本
<parent> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-parent</artifactId> | |
<version>2.1.7.RELEASE</version> | |
<relativePath/> <!-- lookup parent from repository --> | |
</parent> |
2. 引入 spring-redis 的依赖
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-data-redis</artifactId> | |
</dependency> |
二、application.yml 中加入 redis 依赖
spring: | |
datasource: | |
url: jdbc:mysql://localhost:3306/spring_cache?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT | |
driver-class-name: com.mysql.cj.jdbc.Driver | |
username: root | |
password: 123456 | |
redis: | |
host: 39.107.250.174 | |
port: 6379 | |
database: 0 | |
timeout: 1000s # 数据库连接超时时间,2.0 中该参数的类型为 Duration,这里在配置的时候需要指明单位 | |
# 连接池配置,2.0 中直接使用 jedis 或者 lettuce 配置连接池 | |
jedis: | |
pool: | |
# 最大空闲连接数 | |
max-idle: 500 | |
# 最小空闲连接数 | |
min-idle: 50 | |
# 等待可用连接的最大时间,负数为不限制 | |
max-wait: -1 | |
# 最大活跃连接数,负数为不限制 | |
max-active: -1 | |
cache: | |
redis: | |
time-to-live: -1 #毫秒 | |
#以下可忽略 | |
mybatis: | |
configuration: | |
#开启驼峰命名 | |
map-underscore-to-camel-case: true | |
logging: | |
level: | |
com.scitc.cache.mapper : debug |
三、配置编写 redis 配置类
package com.scitc.cache.config; | |
import com.fasterxml.jackson.annotation.JsonAutoDetect; | |
import com.fasterxml.jackson.annotation.PropertyAccessor; | |
import com.fasterxml.jackson.databind.ObjectMapper; | |
import lombok.extern.slf4j.Slf4j; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.boot.context.properties.ConfigurationProperties; | |
import org.springframework.cache.CacheManager; | |
import org.springframework.cache.annotation.CachingConfigurerSupport; | |
import org.springframework.cache.annotation.EnableCaching; | |
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.RedisCacheManager; | |
import org.springframework.data.redis.connection.RedisConnectionFactory; | |
import org.springframework.data.redis.core.RedisTemplate; | |
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; | |
import org.springframework.data.redis.serializer.RedisSerializationContext; | |
import org.springframework.data.redis.serializer.RedisSerializer; | |
import org.springframework.data.redis.serializer.StringRedisSerializer; | |
import java.time.Duration; | |
@Slf4j | |
@Configuration | |
@EnableCaching// 启用缓存,这个注解很重要;// 继承 CachingConfigurerSupport,为了自定义生成 KEY 的策略。可以不继承。public class RedisConfig extends CachingConfigurerSupport {@Value("${spring.cache.redis.time-to-live}") | |
private Duration timeToLive = Duration.ZERO; | |
@Bean(name = "redisTemplate") | |
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, Object> template = new RedisTemplate<>(); | |
template.setConnectionFactory(redisConnectionFactory); | |
// 使用 Jackson2JsonRedisSerializer 来序列化和反序列化 redis 的 value 值 | |
Jackson2JsonRedisSerializer<Object> redisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); | |
ObjectMapper mapper = new ObjectMapper(); | |
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); | |
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); | |
redisSerializer.setObjectMapper(mapper); | |
template.setValueSerializer(redisSerializer); | |
// 使用 StringRedisSerializer 来序列化和反序列化 redis 的 key 值 | |
template.setKeySerializer(new StringRedisSerializer()); | |
template.afterPropertiesSet(); | |
return template; | |
} | |
@Bean | |
public CacheManager cacheManager(RedisConnectionFactory factory) {RedisSerializer<String> redisSerializer = new StringRedisSerializer(); | |
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); | |
// 解决查询缓存转换异常的问题 | |
ObjectMapper om = new ObjectMapper(); | |
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); | |
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); | |
jackson2JsonRedisSerializer.setObjectMapper(om); | |
// 配置序列化(解决乱码的问题)RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() | |
.entryTtl(timeToLive) | |
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) | |
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) | |
.disableCachingNullValues(); | |
RedisCacheManager cacheManager = RedisCacheManager.builder(factory) | |
.cacheDefaults(config) | |
.build(); | |
return cacheManager; | |
} | |
} |
然后我发现有好几篇文章配置 CacheManager 采用的是如下配置:
@Bean | |
public CacheManager cacheManager(RedisConnectionFactory factory) { | |
// 生成一个默认配置,通过 config 对象即可对缓存进行自定义配置 | |
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); | |
// 设置缓存的默认过期时间,也是使用 Duration 设置 | |
config = config.entryTtl(Duration.ofMinutes(1)) | |
.disableCachingNullValues(); // 不缓存空值 | |
// 设置一个初始化的缓存空间 set 集合 | |
Set<String> cacheNames = new HashSet<>(); | |
cacheNames.add("my-redis-cache1"); | |
cacheNames.add("my-redis-cache2"); | |
// 对每个缓存空间应用不同的配置 | |
Map<String, RedisCacheConfiguration> configMap = new HashMap<>(); | |
configMap.put("my-redis-cache1", config); | |
configMap.put("my-redis-cache2", config.entryTtl(Duration.ofSeconds(120))); | |
// 使用自定义的缓存配置初始化一个 cacheManager | |
RedisCacheManager cacheManager = RedisCacheManager.builder(factory) | |
.initialCacheNames(cacheNames) // 注意这两句的调用顺序,一定要先调用该方法设置初始化的缓存名,再初始化相关的配置 | |
.withInitialCacheConfigurations(configMap) | |
.build(); | |
return cacheManager; | |
} |
但经过我使用测试发现,他在 redis 中保存的数据是这样的,并不是 json
后面又找到一篇文章,重新配置 CacheManager (就是我直接贴出来的完整配置代码)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/caojida…
经过测试访问保存的数据格式为 json(下方有图片)
到此 配置完成,正常运行
RedisUtils 工具类
作者:zeng1994
出处:http://www.cnblogs.com/zeng1994/
本文版权归作者和博客园共有,欢迎转载!但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接!
package com.scitc.cache.utils; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.concurrent.TimeUnit; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.data.redis.core.RedisTemplate; | |
import org.springframework.stereotype.Component; | |
import org.springframework.util.CollectionUtils; | |
@Component | |
public class RedisUtil { | |
@Autowired | |
private RedisTemplate<String, Object> redisTemplate; | |
/** | |
* 指定缓存失效时间 | |
* @param key 键 | |
* @param time 时间(秒) | |
* @return | |
*/ | |
public boolean expire(String key,long time){ | |
try {if(time>0){redisTemplate.expire(key, time, TimeUnit.SECONDS); | |
} | |
return true; | |
} catch (Exception e) {e.printStackTrace(); | |
return false; | |
} | |
} | |
/** | |
* 根据 key 获取过期时间 | |
* @param key 键 不能为 null | |
* @return 时间(秒) 返回 0 代表为永久有效 | |
*/ | |
public long getExpire(String key){return redisTemplate.getExpire(key,TimeUnit.SECONDS); | |
} | |
/** | |
* 判断 key 是否存在 | |
* @param key 键 | |
* @return true 存在 false 不存在 | |
*/ | |
public boolean hasKey(String key){ | |
try {return redisTemplate.hasKey(key); | |
} catch (Exception e) {e.printStackTrace(); | |
return false; | |
} | |
} | |
/** | |
* 删除缓存 | |
* @param key 可以传一个值 或多个 | |
*/ | |
@SuppressWarnings("unchecked") | |
public void del(String ... key){if(key!=null&&key.length>0){if(key.length==1){redisTemplate.delete(key[0]); | |
}else{redisTemplate.delete(CollectionUtils.arrayToList(key)); | |
} | |
} | |
} | |
//============================String============================= | |
/** | |
* 普通缓存获取 | |
* @param key 键 | |
* @return 值 | |
*/ | |
public Object get(String key){return key==null?null:redisTemplate.opsForValue().get(key); | |
} | |
/** | |
* 普通缓存放入 | |
* @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) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
return false; | |
} | |
} | |
/** | |
* 递增 | |
* @param key 键 | |
* @param by 要增加几(大于 0) | |
* @return | |
*/ | |
public long incr(String key, long delta){if(delta<0){throw new RuntimeException("递增因子必须大于 0"); | |
} | |
return redisTemplate.opsForValue().increment(key, delta); | |
} | |
/** | |
* 递减 | |
* @param key 键 | |
* @param by 要减少几(小于 0) | |
* @return | |
*/ | |
public long decr(String key, long delta){if(delta<0){throw new RuntimeException("递减因子必须大于 0"); | |
} | |
return redisTemplate.opsForValue().increment(key, -delta); | |
} | |
//================================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) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
return 0; | |
} | |
} | |
/** | |
* 获取 set 缓存的长度 | |
* @param key 键 | |
* @return | |
*/ | |
public long sGetSetSize(String key){ | |
try {return redisTemplate.opsForSet().size(key); | |
} catch (Exception e) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
return null; | |
} | |
} | |
/** | |
* 获取 list 缓存的长度 | |
* @param key 键 | |
* @return | |
*/ | |
public long lGetListSize(String key){ | |
try {return redisTemplate.opsForList().size(key); | |
} catch (Exception e) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
return null; | |
} | |
} | |
/** | |
* 将 list 放入缓存 | |
* @param key 键 | |
* @param value 值 | |
* @param time 时间(秒) | |
* @return | |
*/ | |
public boolean lSet(String key, Object value) { | |
try {redisTemplate.opsForList().rightPush(key, value); | |
return true; | |
} catch (Exception e) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
return false; | |
} | |
} | |
/** | |
* 将 list 放入缓存 | |
* @param key 键 | |
* @param value 值 | |
* @param time 时间(秒) | |
* @return | |
*/ | |
public boolean lSet(String key, List<Object> value) { | |
try {redisTemplate.opsForList().rightPushAll(key, value); | |
return true; | |
} catch (Exception e) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
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) {e.printStackTrace(); | |
return false; | |
} | |
} | |
/** | |
* 移除 N 个值为 value | |
* @param key 键 | |
* @param count 移除多少个 | |
* @param value 值 | |
* @return 移除的个数 | |
*/ | |
public long lRemove(String key,long count,Object value) { | |
try {Long remove = redisTemplate.opsForList().remove(key, count, value); | |
return remove; | |
} catch (Exception e) {e.printStackTrace(); | |
return 0; | |
} | |
} | |
} |
自己遇到的问题
发现了个问题(不是配置文件的问题),我的对象实体类是这样的
@Data | |
public class Employee implements Serializable { | |
private Integer id; | |
private String lastName; | |
private String email; | |
private Integer gender; // 性别 1 男 0 女 | |
// private Integer userId; | |
private Integer dId; | |
} |
在 json 数据中多了一个 did,
但获取然后打印出来并没有多数据
emp:Employee(id=2, lastName= 李四, email=132456798@qq.com, gender=0, dId=1)
问了大佬说是命名问题
当把 Employee 中的 dId 改成 userId 时(以及修改数据库字段)
这次 userId 居然不重复,后面吧 dId 换成了 uId,依旧重复。emmm 玄学。。。
最开始不知道集成 redis 怎么在业务中使用,根据自己理解发现,当你配置了 redis,SpringBoot 会自动把缓存加到 redis 中,并不使用默认的
@Cacheable(value = {"emp"},key = "#id") | |
public Employee getEmp(Integer id){log.info("查询" + id + "号员工"); | |
Employee employee = employeeMapper.getEmpById(id); | |
return employee; | |
} |
因为配置了 redis 所以,使用 redis 缓存不使用默认的
正文完