携手创作,共同成长!这是我参与「掘金日新计划 · 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 的分享!
如果您觉得本文不错,欢迎点赞支持,您的关注是我坚持的动力!