Spring Boot(三) 快速使用 Redis

167 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

大家好! 我是慕歌,一只想教你学习 Spring Boot的野生coder! 欢迎来到慕歌的 Sping boot系列教程,希望通过这个教程带大家搭建基础的 Spring Boot项目,该教程所有知识点均来源于本人的真实开发!

前言

不知不觉间,慕歌已经连续更新了一周了,在这一周的内容选择中,我选择了现在使用最为熟练的spring boot 。但是但真正开始写自己的总结文章时,发现自己对于spring boot 的理解还有待提升。以后每一个知识点,我都将用两到三篇文章讲解,第一篇文章主要是进行基础配置,后面的文章深入开发环境中,谈论开发场景与应用。在后面的文章中,我将以更加完备的知识体系,做优质技术分享。

应用场景

缓存:

作为Key-Value形态的内存数据库,Redis 最先会被想到的应用场景便是作为数据缓存,spring boot 也为我们提供了以redis 为缓存的缓存依赖。而使用 Redis 缓存数据非常简单,只需要将对象通过需要的序列化方式序列化成string 对象就可以直接保存,序列化后的数据具有更高的可读性,在开发中我常序列化为json 数据格式具有更高的可读性,不过也有一些需要注意的地方:

  • 必须保证不同对象的 key 不会重复,并且使 key 尽量短,一般使用类名(表名)加主键拼接而成。
  • 选择一个优秀的序列化方式也很重要,目的是提高序列化的效率,减少内存占用以及优秀的可读性。
  • 缓存内容与数据库的一致性,这里一般有两种做法:
    • 只在数据库查询后将对象放入缓存,如果对象发生了修改或删除操作,直接清除对应缓存(或设为过期)。
    • 在数据库新增和查询后将对象放入缓存,修改后更新缓存,删除后清除对应缓存(或设为过期)。

上述的做法只是考虑简单业务下的一种思路,在并发情况下,需要考虑的点将异常复杂!

/**
 * Redis 配置类
 */
@Configuration
public class RedisConfig {
    @Bean(name = "template")
    public RedisTemplate<String, Object> template(RedisConnectionFactory factory) {
        // 创建RedisTemplate<String, Object>对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(factory);
        // 定义Jackson2JsonRedisSerializer序列化对象
        Jackson2JsonRedisSerializer<Object> 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.activateDefaultTyping(
                LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.WRAPPER_ARRAY);
        jacksonSeial.setObjectMapper(om);
        StringRedisSerializer stringSerial = new StringRedisSerializer();
        // redis key 序列化方式使用stringSerial
        template.setKeySerializer(stringSerial);
        // redis value 序列化方式使用jackson
        template.setValueSerializer(jacksonSeial);
        // redis hash key 序列化方式使用stringSerial
        template.setHashKeySerializer(stringSerial);
        // redis hash value 序列化方式使用jackson
        template.setHashValueSerializer(jacksonSeial);
        template.afterPropertiesSet();
        return template;
    }
}

短信验证码:

在登录的过程中,少不了使用验证码的场景,那么验证码如何实现定时过期,一次有效,异端使用等功能的,他都离不开redis 服务的特性,能够配置一个值的有效期,当在这个有效期内验证码还没有被使用,那么redis就会删除该字段。并且redis服务器可以独立于我们的spring boot 服务器,该服务器可通过配置连接访问。

/**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key      缓存的键值
     * @param value    缓存的值
     * @param timeout  时间
     * @param timeUnit 时间颗粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
        RBucket<T> result = redissonClient.getBucket(key);
        result.set(value);
        result.expire(timeout, timeUnit);
    }

    /**
     * 设置有效时间
     *
     * @param key     Redis键
     * @param timeout 超时时间
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置有效时间
     *
     * @param key     Redis键
     * @param timeout 超时时间
     * @param unit    时间单位
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
        RBucket rBucket = redissonClient.getBucket(key);
        return rBucket.expire(timeout, unit);
    }

计数器:

例如:文章的阅读量、微博点赞数、允许一定的延迟,先写入Redis再定时同步到数据库

计数功能应该是最适合 Redis 的使用场景之一了,因为它高频率读写的特征可以完全发挥 Redis 作为内存数据库的高效。在 Redis 的数据结构中,string、hash和sorted set都提供了incr方法用于原子性的自增操作,下面举例说明一下它们各自的使用场景:
如果应用需要显示每天的注册用户数,便可以使用string作为计数器,设定一个名为REGISTERED_COUNT_TODAY的 key,并在初始化时给它设置一个到凌晨 0 点的过期时间,每当用户注册成功后便使用incr命令使该 key 增长 1,同时当每天凌晨 0 点后,这个计数器都会因为 key 过期使值清零。
每条记录都有点赞数、评论数、转发数和浏览数四条属性,这时用hash进行计数会更好,将该计数器的 key 设为weibo:weibo_id,hash的 field 为like_number、comment_number、forward_number和view_number,在对应操作后通过hincrby使hash 中的 field 自增。

全局配置:

在程序运行中,总是需要抽取一次公共配置为整个工程服务,这些工程不依赖具体的请求独立运行,并且在之后的开发中全局可用。

/**
     * 项目启动时,初始化参数到缓存
     */
    @PostConstruct
    public void init() {
        configService.loadingConfigCache();
    }

    @Override
    public  List<Config> loadingConfigCache() {
        List<Config> list = this.list();
        redisUtils.set("config:loadingConfigCache",list);
        return list;
    }

结语

这一章的分享到这里就结束了,下一节中还将带来redis 的分享!
如果您觉得本文不错,欢迎点赞支持,您的关注是我坚持的动力!