Redis入门到入坑(三)

1.Redis内存淘汰策略

数据存放在内存中,可能会导致内存超过负荷,为防止内存撑爆,衍生出内存淘汰策略进行预防

在Redis中主要存在种淘汰策略:

1)noeviction:当内存使用达到阈值的时候,执行命令会直接报错
2)allkeys-lru:在所有的key之中,优先移除最近未使用的key(推荐)
3volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key
4)allkeys-random:在所有的key之中,随机移除某个key
5volatile-random:在设置了过期时间的键空间中,随机移除某个key
6volatile-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 被其他命令所改动,那么后续的事务将被打断,也就是取消提交事务


版权声明:本文为weixin_43911969原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。