持久化
redis是内存数据库,服务器重启,数据会丢失
持久化机制:
- RDB:默认方式,不需要进行配置
在一定的间隔事件中,检测key的变化情况,然后持久化数据 - AOF:日志记录的方式,记录每一条命令的操作,可以每次命令操作后,持久化数据
RDB
在redis.windows.conf文件中修改配置
# 在15分钟有至少1个key改变持久化一次
save 900 1
# 在5分钟有至少10个key改变持久化一次
save 300 10
# 在1分钟有至少 10000个key改变持久化一次
save 60 10000
持久化后会生成一个rdb文件,保存持久化的数据
可以在redis安装目录使用命令指定配置文件
redis-server.exe redis.windows.conf
AOF
编辑配置文件redis.windows.conf
appendonly默认是no,改为yes
有三个配置
#appendfsync always:每一次操作都进行持久化
appendfsync everysec:每隔一秒进行一次持久化
#appendfsync no:不进行持久化
会生成一个aof类型的持久化文件
java客户端 Jedis
一款Java操作redis数据库的工具
<!--连接池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.3</version>
</dependency>
Jedis操作redis的方法和redis命令相同
jedis连接池 JedisPool
getResource()方法得到jedis对象
连接池主要配置连接池参数,使用很简单。
spring-data-redis
RedisTemplate高度封装了jedis,自动管理连接池
RedisTemplate API | 原生Redis指令 | 说明 |
---|---|---|
public void delete(K key) | DEL key [key …] | 删除给定的一个或多个 key |
public Boolean hasKey(K key) | EXISTS key | 检查给定 key 是否存在 |
public Boolean expire/expireAt(…) | EXPIRE key seconds | 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。 |
public Long getExpire(K key) | TTL key | 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。 |
RedisTemplate中定义了对5种数据结构操作
redisTemplate.opsForValue();//操作字符串
redisTemplate.opsForHash();//操作hash
redisTemplate.opsForList();//操作list
redisTemplate.opsForSet();//操作set
redisTemplate.opsForZSet();//操作有序set
这五种类型得到对应的Operations,再去操作redis
可以直接使用boundXXXOps
BoundValueOperations
BoundSetOperations
BoundListOperations
BoundSetOperations
BoundHashOperations
opsForXXX和boundXXXOps的区别
XXX为Value的类型,前者获取一个operator,但是没有指定操作的对象(key),可以在一个连接(事务)内操作多个key以及对应的value;后者获取了一个指定的对象(key)的operator,在一个连接(事务)内只能操作这个对应的key。
RedisTemplate配置
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 值采用json序列化
template.setValueSerializer(jacksonSeial);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
// 设置hash key 和value序列化模式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
return template;
}
redis序列化策略不同会导致redisTemplate.opsForValue().get不到数据
序列化反序列化的多种选择策略
JdkSerializationRedisSerializer:POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略。
StringRedisSerializer:Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。
JacksonJsonRedisSerializer:jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】
OxmSerializer:提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】
Redis数据缓存
package org.jeecg.common.api.vo;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
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.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* redis配置类
**/
@Configuration
@EnableCaching//开启注解式缓存
//继承CachingConfigurerSupport,为了自定义生成KEY的策略。可以不继承。
public class RedisConfig extends CachingConfigurerSupport {
/**
* 生成key的策略 根据类名+方法名+所有参数的值生成唯一的一个key
* @return
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
/**
* 管理缓存
* @param redisConnectionFactory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
//通过Spring提供的RedisCacheConfiguration类,构造一个自己的redis配置类,从该配置类中可以设置一些初始化的缓存命名空间
// 及对应的默认过期时间等属性,再利用RedisCacheManager中的builder.build()的方式生成cacheManager:
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 生成一个默认配置,通过config对象即可对缓存进行自定义配置
config = config.entryTtl(Duration.ofHours(1)) // 设置缓存的默认过期时间,也是使用Duration设置
.disableCachingNullValues(); // 不缓存空值
// 设置一个初始化的缓存空间set集合
Set<String> cacheNames = new HashSet<>();
cacheNames.add("cache1");
cacheNames.add("cache2");
// 对每个缓存空间应用不同的配置
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("cache1", config);
configMap.put("cache2", config.entryTtl(Duration.ofSeconds(1200)));
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory) // 使用自定义的缓存配置初始化一个cacheManager
.initialCacheNames(cacheNames) // 注意这两句的调用顺序,一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
.withInitialCacheConfigurations(configMap)
.build();
return cacheManager;
}
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(factory);
return stringRedisTemplate;
}
}
使用缓存
//表示使用cache2缓存空间,key的生成策略为book+id,当id>2的时候才会使用缓存
@Cacheable(value = "cache2",key = "'book'+#id",condition = "#id>2")
public Book selectByPrimaryKey(Integer id) {
return this.bookMapper.selectByPrimaryKey(id);
}
@Cacheable: 作用是主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
主要参数说明:
-
value : 缓存的名称,在 spring 配置文件中定义,必须指定至少一个
例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}。 -
key :缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合,
例如:@Cacheable(value=”testcache”,key=”#userName”)。 -
condition :缓存的条件,可以为空
@CachePut: 作用是主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实查询
主要参数说明: 参数配置和@Cacheable一样
@CacheEvict: 作用是主要针对方法配置,能够根据一定的条件对缓存进行清空
主要参数说明:
-
value , key 和 condition 参数配置和@Cacheable一样。
-
allEntries :是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存
-
beforeInvocation :是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存
@CacheEvict(value = "cache2",allEntries = true)
public void clear(){
System.out.println("cache2槽里的所有缓存被清除....");
}
Redis集群配置
public class RedisConfig {
protected Logger LOG = LoggerFactory.getLogger(this.getClass());
@Value("${spring.redis.cluster.nodes}")
private String clusterNodes;
@Bean
public JedisCluster getJedisCluster() {
String[] cNodes = clusterNodes.split(",");
LOG.info("连接redis ips-->{}", JSON.toJSONString(cNodes));
Set<HostAndPort> nodes = new HashSet<>();
//分割出集群节点
for (String node : cNodes) {
String[] hp = node.split(":");
nodes.add(new HostAndPort(hp[0], Integer.parseInt(hp[1])));
}
JedisPoolConfig jedisPoolConfig = getJedisPoolConfig();
// 最大空闲连接数, 默认8个
jedisPoolConfig.setMaxIdle(100);
// 最大连接数, 默认8个
jedisPoolConfig.setMaxTotal(500);
//最小空闲连接数, 默认0
jedisPoolConfig.setMinIdle(0);
// 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
jedisPoolConfig.setMaxWaitMillis(2000); // 设置2秒
//对拿到的connection进行validateObject校验
jedisPoolConfig.setTestOnBorrow(true);
//创建集群对象
// return new JedisCluster(nodes, 5000,5000,5,"seaking", jedisPoolConfig);
return new JedisCluster(nodes, 5000,jedisPoolConfig);
}
}
通过getJedisCluster()得到JedisCluster 去操作redis。
因为集群中链接是对一个节点连接,使用命令的时候才会去连接,所以有些单机可以是用的命令不可以用,其余使用方法和jedis相同。