What:Redis简介
redis官方文档:https://developer.redis.com
redis是一种(key-value)的nosql类型的数据直接在内存里面进行缓存。
redis使用场景
1、热点数据缓存
由于redis访问速度块、支持的数据类型比较丰富,所以redis很适合用来存储热点数据,另外结合expire,我们可以设置过期时间然后再进行缓存更新操作。
2、限时业务场景使用(注册验证码、短信验证码)
redis中可以使用expire命令设置一个键的生存时间,到时间后redis会删除它。利用这一特性可以运用在限时的优惠活动信息、手机验证码等业务场景。
3、计数器相关问题
redis由于incrby命令可以实现原子性的递增,所以可以运用于高并发的秒杀活动、分布式序列号的生成、具体业务还体现在比如限制一个手机号发多少条短信、一个接口一分钟限制多少请求、一个接口一天限制调用多少次等等。
4、点赞、关注好友等存储
Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。 又或者在微博应用中,每个用户关注的人存在一个集合中,就很容易实现求两个人的共同好友功能。
redis主要特点
1)支持数据的持久化,可以将内存中的数据持久化保存在磁盘中,重启后再次将磁盘中的数据加载到内存。
2)丰富的数据类型,不仅支持简单的key-value类型的数据,还提供List、Set、ZSet、Hash等数据结构的存储。
3)支持数据的备份,即master-slave(主-从)模式的数据备份。
4)丰富的特性,支持publish/subscribe(发布/订阅)、通知、key过期等特性。
redis数据类型
Why:为什么要使用redis
在之前的单机业务下我们服务端的模式是 app -> DAO -> MySql这种情况家要进行大量的io读写操作。从而导致效率不高。同时也使得mysql的性能会很差(这里引用别人博客的图片)
引入缓存之后如今的模式是 app -> DAO -> Cache -> MySql 从而DAO层可以直接从缓存中读取数据,
redis优势
Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
Redis支持数据的备份,即master-slave模式的数据备份。
性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
How:SpringBoot集成redis
1、RedisTemplate
RedisTemplate有两个方法经常用到:
opsForXXX()和boundXXXOps(),XXX是value(值)的数据类型。
opsForXXX获取到一个操作(Operation),但是没有指定操作的key(键),可以在一个连接(事务)内操作多个key以及对应的value;boundXXXOps获取到一个指定key的操作,在一个连接内只操作这个key对应的value。
//操作string
redisTemplate.opsForValue().set("key","value");
//操作hash
redisTemplate.opsForHash().put("key","people","tom");
//操作list
redisTemplate.opsForList().leftPush("key","value");
//操作set
redisTemplate.opsForSet().add("key","1","2","3");
//操作zset
redisTemplate.opsForZSet().add("key" , "test");
2、BoundValueOperations操作
String value = "weiz";
BoundValueOperations operations = redisTemplate.boundValueOps(value);
operations.xxx;
spring集成redis
1、pom依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.5.4</version> </dependency>
2、修改配置文件
spring.redis.database = 0 spring.redis.host = 127.0.0.1 spring.redis.port =6379 spring.redis.password = spring.redis.jedis = # 最大链接数 spring.redis.pool.max-active = 8 # 最大等待时间-1表示没有 spring.redis.pool.max-wait = -1 # 最大空闲数量 spring.redis.pool.max-idle = # 最小空闲数量 spring.redis.pool.min-idle = 2
配置序列化方式
@Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer(); GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); // 设置值(value)的序列化采用FastJsonRedisSerializer。 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // redisTemplate.setHashValueSerializer(fastJsonRedisSerializer); // 设置键(key)的序列化采用StringRedisSerializer。 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
测试类
@Test void zz() throws InterruptedException { Book book = new Book(); book.setBookToken(environment.getProperty("cfg.random.value")); book.setSaleUid(environment.getProperty("cfg.random.uuid")); book.setDescription("test for redis"); book.setAuthor("Hall Way"); book.setId(1L); book.setUpdatetimestamp(DateUtil.date()); book.setCreatetimestamp(DateUtil.date()); //存储对象 redisTemplate.opsForValue().set("book:"+ book.getId().toString() , book); System.out.println(redisTemplate.opsForValue().get("book:1")); } /** 结果 Book(id=1, bookName=null, description=test for redis, author=Hall Way, bookToken=2af9cc2845c47ab3e0525160cabd3c34, saleUid=22dcd988-c60d-4877-97fb-ad6dcc9b718b, createtimestamp=2022-06-10 14:58:37, updatetimestamp=2022-06-10 14:58:37) */
Spring使用redis做缓存
原理架构图如下
代码实操
1、开启缓存
@Configuration @EnableCaching public class RedisCacheConfig extends CachingConfigurerSupport { /** * 采用RedisCacheManager作为缓存管理器 * 同时为了高可用Redis,可以使用RedisSentinelConfiguration来支持Redis Sentinel * */ @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).build(); return cacheManager; } }
@Configuration:标识它是配置类的注解。
@EnableCaching:开启基于注解的缓存,也可以写在启动类上。
@SpringBootApplication @MapperScan("com.practise.mapper.**") @EnableScheduling @EnableCaching public class MyStart { public static void main(String[] args) { SpringApplication.run(MyStart.class); } }
2、添加@Cacheable注解
在读取数据的方法上添加@Cacheable注解or在controller层上@Cacheable注解。
这样就会自动将该方法获取的数据结果放入缓存。若没有数据则从数据库中读取之后就会放入缓存当中。
一:没有缓存的情况
数据库:
controller:
@Cacheable("book") //命名空间 @GetMapping("book/{id}") public Book getDetail(@PathVariable Long id){ System.out.println("请求详细书籍信息"); return bookService.getDetail(id); }
service:
public Book getDetail(Long id){ Book resultBook = Optional.ofNullable(getById(id)) .orElseThrow(()->new RuntimeException("没有找到该书籍")); System.out.println("本次数据来源于数据库"); return resultBook; }
启动之后输入localhost:8080/book/1
控制台:
查看redis中发现多出了数据
redis常用缓存注解
1、常用注解和参数
spring提供了@EnableCaching、@Cacheable、@CacheEvict、@CachePut、@CacheConfig五个注解来实现缓存