springboot 使用 redis作为缓存,简单的demo
文章目录
- 安装redis
- windows安装
- 搭建springboot+redis项目
- 代码
- DemoController.java
- DemoService.java
- DemoServiceImpl.java
- RedisConf.java
- application.yml
- 不缓存的测试
- 了解几个注解
- 添加缓存测试
- 查看redis里面的缓存
- 设置缓存失效时间
- 总结
安装redis
windows安装
下载地址 解压之后启动redis服务
redis-server.exe redis.windows.conf
然后使用客户端连接,redis-cli.exe可以连接默认是 127.0.0.1:6379
搭建springboot+redis项目
使用的工具是idea
pom.xml文件内容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mucong</groupId>
<artifactId>springbootrediscache</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.8</version>
</dependency>
</dependencies>
</project>
代码
为了测试效果,我们设计了一个接口获取当前的时间,这样每次获取的都是最新的时间,如果增加了缓存,就可能获取之前的时间,实际项目中不能这么用,实际项目为了保证接口的幂等性,如果有时间的话,一般会把时间作为参数。
项目结构
App.java
package com.mucong.srcache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
DemoController.java
ppackage com.mucong.srcache.controller;
import com.mucong.srcache.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/demo")
public class DemoController {
@Autowired
private DemoService demoService;
@GetMapping("/getNow")
public String getNow(String key) throws Exception{
return demoService.getTime(key);
}
}
DemoService.java
package com.mucong.srcache.service;
public interface DemoService {
String getTime(String key);
}
DemoServiceImpl.java
package com.mucong.srcache.service.impl;
import com.mucong.srcache.service.DemoService;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Service
public class DemoServiceImpl implements DemoService {
@Override
public String getTime(String key) {
return LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
}
}
RedisConf.java
package com.mucong.srcache.conf;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration
@EnableCaching
public class RedisConf extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setConnectionFactory(factory);
//key序列化方式
template.setKeySerializer(redisSerializer);
//value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
// 可以给每个cacheName不同的RedisCacheConfiguration 设置不同的过期时间
//.withCacheConfiguration("Users",config.entryTtl(Duration.ofSeconds(100)))
.transactionAware()
.build();
return cacheManager;
}
}
application.yml
server:
port: 9000
spring:
redis:
database: 0
host: 127.0.0.1
port: 6379
password: #默认是不需要的
jedis:
pool:
max-active: 8
timeout: 5000
#logging:
# level:
# root: debug
不缓存的测试
上面的代码还没有添加缓存
启动项目
浏览器中输入 http://localhost:9000/demo/getNow/abc
每次刷新返回的时间都不同
!
了解几个注解
简单介绍几个注解,待会要用到
- @EnableCaching
- @Cacheable
- @CachePut
- @Caching
- @CacheConfig
- @CacheEvict
注解 | 说明 | 作用对象 |
EnableCaching | 开启缓存的开关,放到配置类上,也可以直接放到App上 | 全局的 |
CacheConfig | 标注到类上,主要设置公共属性,缓存空间,key生成策略,缓存管理器 | 设置的类内部 |
Cacheable | 标注到方法上,使用缓存的主方法,逻辑是,根据key如果有缓存则返回缓存数据,没有则执行方法,并且把数据放入缓存 | 方法上 |
CachePut | 放到方法上,更新缓存,方法的返回值根据设置的key值放入缓存 | 方法上 |
CacheEvict | 放到方法上,清除缓存,一般设置在编辑或者删除操作的方法上,清除对应key值的缓存 | 方法上 |
Caching | diy方式 | 方法上 |
添加缓存测试
通过上面的注解,我们首先需要开启缓存,在App.java中添加注解@EnableCaching,
然后修改DemoServiceImpl.java,然后重启项目。
刷新页面发现每次时间都相同,修改key值之后,可以返回时间
查看redis里面的缓存
使用的工具是 redisDesktopManager,可以看到里面的缓存有个时间,TTL缓存失效的时间单位是秒。
设置缓存失效时间
在RedisConf.java文件中,修改里面的参数,我们可以设置到application.yml中
在文件中设置属性,默认我们用600秒
修改代码
现在我们可以在application.yml中设置过期时间了,使用后发现时间变长了
总结
这里只是简单介绍一下应用,我们在使用中会发现会有很多细节需要掌握,比如过期策略,缓存穿透,雪崩,key冲突,还有redis单点到哨兵模式,这些我们都可以一点一点使用中摸索出来。