1.Redis内存淘汰策略
数据存放在内存中,可能会导致内存超过负荷,为防止内存撑爆,衍生出内存淘汰策略进行预防
在Redis中主要存在种淘汰策略:
1)noeviction:当内存使用达到阈值的时候,执行命令会直接报错
2)allkeys-lru:在所有的key之中,优先移除最近未使用的key(推荐)
3)volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key
4)allkeys-random:在所有的key之中,随机移除某个key
5)volatile-random:在设置了过期时间的键空间中,随机移除某个key
6)volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除
其实按照这里面的介绍可以看出来,最优2才是最好的,其他的都有可能将重要的key淘汰
2.配置Redis淘汰策略
在redis.conf中可以指定淘汰策略。
maxmemory :可以指定内存的阈值大小(maxmemory 100mb)
maxmemory-policy volatile-lru:可以指定使用什么淘汰策略
3.Redis中的自动过期机制
自动过期策略主要针对设置了过期时间的key,比如我们在支付的时候,拥有未支付、订单已过期、已支付三种状态。
其实实现这三种状态我们可以使用Redis的过期机制+回调的形式执行,当然,也有其他的办法,比如:使用定时任务30分钟后检查
、按照每分钟轮训检查
4.SpringBoot整合key失效监听
整合key失效监听其实很简单,我们只需要自行注入bean即可完成。
首先需要更改redis.conf的配置,打开key监听——>notify-keyspace-events “Ex”
// 注册监听
@Configuration
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
}
// 实体类
@Data
public class Entity {
private Long id;
private String name;
/**
* 0 待支付 1 已经支付
*/
private Integer status;
private String token;
private String orderId;
public OrderEntity(Long id, String orderName, String orderId, String token) {
this.id = id;
this.name = name;
this.orderId = orderId;
this.token = token;
}
}
// 数据查询
public interface Mapper {
@Insert("insert into number values (null,#{name},0,#{token},#{orderId})")
int insert(Entity entity);
@Select("SELECT ID ,name ,status,token,order_id as orderId FROM number where order_token=#{token};")
OrderEntity getNumber(String token);
@Update("update number set status=#{status} where token=#{token};")
int updateStatus(String token, Integer status);
}
// controller层
@RestController
public class Controller {
@Autowired
private Mapper mapper;
@Autowired
private RedisUtils redisUtils;
@RequestMapping("/save")
public String save() {
// 1.生成token
String token = UUID.randomUUID().toString();
String orderId = System.currentTimeMillis() + "";
//2. 将该token存放到redis中
redisUtils.setString(token, orderId, 7L);
Entity entity = new Entity(null, "会员", orderId, token);
int result = mapper.insert(entity);
return result > 0 ? "success" : "fail";
}
}
// 监听事务
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
* 待支付
*/
private static final Integer ORDER_STAYPAY = 0;
/**
* 失效
*/
private static final Integer ORDER_INVALID = 2;
@Autowired
private Mapper mapper;
/**
* Redis失效事件 key
*
* @param message
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
String expiraKey = message.toString();
// 根据key查询 value 如果还还是为待支付状态 将订单改为已经超时~~
Entity entity = mapper.getNumber(expiraKey);
System.out.println(expiraKey);
if (entity == null) {
return;
}
if (entity.getOrderStatus().equals(ORDER_STAYPAY)) {
// 将订单状态改为已经失效
mapper.updateStatus(expiraKey, ORDER_INVALID);
}
}
}
5.Redis事务操作
Redis不存在事务的回滚,但是提供取消事务
Multi:开启事务(在开启事务之后,其他的线程依旧可以做其他的事情)
EXEC:提交事务
Watch:监听(监听key在提交事务之前,是否发生了改变,如果发生过变化,则无法提交数据 )
Redis中的事务和MySQL事务的区别:
MySQL开启事务会触发行锁,只会进行一个操作;Redis开启事务会将所有的get、set存储起来,后续一个个执行,如果多个事务进行set对一个key进行操作,那么就会导致,只有最后一个set生效
为了解决上面提到的Redis事务的问题,出来了一个Watch,它主要是用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么后续的事务将被打断,也就是取消提交事务