Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
Redis支持数据的备份,即master-slave模式的数据备份。
第一步:
pom.xml文件:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
第二步:
application.properties文件:
spring.redis.database=0
# redis server host
spring.redis.host=127.0.0.1
# redis password
spring.redis.password=
# connection port
spring.redis.port=6379
# time out
spring.redis.timeout=10000
# 配置缓存过期时间
spring.redis.expiretime=1800
# pool settings:
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# set Key prefix.
# spring.cache.redis.key-prefix=dev
# Entry expiration in milliseconds. By default the entries never expire.
spring.cache.redis.time-to-live=1d
# Whether to use the key prefix when writing to Redis.
spring.cache.redis.use-key-prefix=true
第三步:
编写RedisConfig文件:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
import java.time.Duration;
//@EnableCaching 【重点】不能加,不然@Cacheable无效
@Configuration
//加载该前缀的配置信息,提供set方法即可自动注入
@ConfigurationProperties(prefix = "spring.cache.redis")
public class RedisConfig extends CachingConfigurerSupport{
private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);
private Duration timeToLive = Duration.ZERO;
public void setTimeToLive(Duration timeToLive) {
this.timeToLive = timeToLive;
}
/**
* 自定义生成redis-key
*
* @return
*/
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName()).append(".");
sb.append(method.getName()).append(".");
for (Object obj : objects) {
sb.append(obj.toString());
}
log.info("------> 自定义生成redis-key完成,keyGenerator=" + sb.toString());
return sb.toString();
}
};
}
/* @Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
//【重点】【new RedisCacheManager()在 springboot2.x 里无效】
RedisCacheManager manager = new RedisCacheManager(redisTemplate);
manager.setUsePrefix(true);
RedisCachePrefix cachePrefix = new RedisPrefix("prefix");
manager.setCachePrefix(cachePrefix);
// 整体缓存过期时间
manager.setDefaultExpiration(3600L);
// 设置缓存过期时间。key和缓存过期时间,单位秒
Map expiresMap = new HashMap<>();
expiresMap.put("user", 1000L);
manager.setExpires(expiresMap);
return manager;
}*/
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(this.timeToLive)
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
.disableCachingNullValues();
RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
log.info("------> 自定义RedisCacheManager加载完成");
return redisCacheManager;
}
@Bean(name = "redisTemplate")
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(keySerializer());
redisTemplate.setHashKeySerializer(keySerializer());
redisTemplate.setValueSerializer(valueSerializer());
redisTemplate.setHashValueSerializer(valueSerializer());
log.info("------> 自定义RedisTemplate加载完成");
return redisTemplate;
}
private RedisSerializer keySerializer() {
return new StringRedisSerializer();
}
private RedisSerializer
springboot2.X RedisCacheManager已经没有了单参数的构造方法 ,参考文档
第四步:
注解需要缓存的地方
@Service("UserService")
//对应ehcache.xml文件里面的
@CacheConfig(cacheNames = "user")
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
//无论怎样,都将方法的返回结果放到缓存当中。
//ehcache3 会自动处理要缓存的key-value里面的key
@CachePut
public void save(User user) {
System.out.println("新增功能,更新缓存,直接写库, id=" + user);
userRepository.save(user);
}
@Override
@CachePut
public void update(User user) {
System.out.println("更新功能,更新缓存,直接写库, id=" + user);
userRepository.save(user);
}
@Override
//将一条或者多条数据从缓存中删除。
@CacheEvict
public void remove(Long userId) throws Exception {
System.out.println("删除功能,删除缓存,直接写库, id=" + userId);
userRepository.deleteById(userId);
}
@Override
@CacheEvict
public void batchRemove(Long[] userIds) throws Exception {
for (Long userId : userIds) {
userRepository.deleteById(userId);
}
}
@Override
public List getUserList() {
return userRepository.findAll();
}
@Override
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
@Override
//在方法执行前Spring先是否有缓存数据,如果有直接返回。如果没有数据,调用方法并将方法返回值存放在缓存当中。
@Cacheable
public User findById(long id) {
//可以在这里打一个断点,发现第二次查询不会被断点卡到为配置成功
System.out.println("查询功能,缓存找不到,直接读库, id=" + id);
return userRepository.findById(id);
}
}
第五步:
配置启动文件:
@SpringBootApplication
@EnableCaching//开启缓存
@PropertySource("application.properties")
public class XXXApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(XXXApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(XXXApplication.class, args);
}
}
可能出现的问题:
1、 类型转换出现问题:看看是不是工程里面加入了热部署,注释掉热部署即可
java.lang.ClassCastException:
com.XXX.system.UserDO cannot be cast to com.XXX.system.UserDO
2、这里涉及redis的常见操作:
查看key的类型
type key
查看所有key
keys *
删除一个key
DEL key
清空一个DB
FLUSHDB
清空所有
FLUSHALL
切换到其他DB
select 1
可能的问题:
WRONGTYPE Operation against a key holding the wrong kind of value
原因是:类型不一致,使用redis命令不当造成的。
例如:
127.0.0.1:6379> keys *
1) "user~keys"
2) "user_1"
127.0.0.1:6379> get user~keys
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> type user~keys
zset
127.0.0.1:6379> zrange user~keys 0 10
1) "user_1"
参考文档:
https://blog.csdn.net/guokezhongdeyuzhou/article/details/79789629
https://blog.csdn.net/Mirt_/article/details/80934312
https://blog.csdn.net/xieliaowa9231/article/details/78995465