为啥要启用缓存
- 提高性能,针对同一个方法,当再次请求时传递的参数没发生变化时,直接返回上次查询的结果,不再执行方法中的业务逻辑
开启缓存
- 在启动类添加@EnableCaching 注解
- 在方法上使用 @Cacheable(value = “user”,key = “#p0”)注解,key和value可以自定义。
解释
@Cacheable(value = "user",key = "#p0")
value表示此缓存内容的缓存位置,不同方法的value应该使用不一样的值防止被覆盖。
key中的#p0表示方法的第一个参数值,当再次请求此方法,传递的值如果没发生变化,则直接从缓存中取,不再执行方法中的代码。
实验
做一个实验,把两个不同的方法key和vaue设置成一样,并且分别请求这两个方法,请求的时候参数值也给他传一样的,只有请求路径不一样,请求如下:
@RestController
@RequestMapping("/testBoot")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("getUser/{id}")
@Cacheable(value = "user",key = "#p0")
public User GetUser(@PathVariable int id){
System.out.println("test.....");
return userService.Sel(id);
}
@RequestMapping("getUsers/{id}")
@Cacheable(value = "user",key = "#p0")
public List<User> getUsers(@PathVariable int id){
System.out.println("getuesrs.....");
return userService.getUsers();
}
}
实验一,验证缓存成功
第一次请求http://localhost:8080/testBoot/getUsers/3,可以看到结果如下:
此时我们把数据库中张三的money随便改成其他数字,再次请求http://localhost:8080/testBoot/getUsers/3会发现查出来的结果没变,说明我们设置的缓存生效了。
实验二,验证缓存名字冲突
接着上边,这次请求http://localhost:8080/testBoot/getUser/3,请求路径变了,参数依然是3,结果如下:
原因:因为这请求执行的方法缓存的地址名也叫user,并且传递的参数也是3,所以程序认为此次请求应该直接从缓存获取结果,不用再执行代码。于是乎它就从程序获取到上次缓存的List 并且想把它反序列化成User,结果就报错java.lang.ClassCastException
整合redis
加入redis后,会自动把缓存放到redis中管理
- 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置redis
spring:
redis:
database: 9
host: 192.168.2.250
password: sonoscape
port: 6379
ssl: false
timeout: 5000 # Connection timeout.
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.*;
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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import javax.annotation.Resource;
import static org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig;
@Configuration
public class CacheConfig extends CachingConfigurerSupport {
@Resource
private RedisConnectionFactory factory;
/**
* 自定义生成redis-key
*
* @return
*/
@Override
@Bean
public KeyGenerator keyGenerator() {
return (o, method, objects) -> {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName()).append(".");
sb.append(method.getName()).append(".");
for (Object obj : objects) {
sb.append(obj.toString());
}
System.out.println("keyGenerator=" + sb.toString());
return sb.toString();
};
}
@Bean
public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
redisTemplate.setKeySerializer(genericJackson2JsonRedisSerializer);
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
return redisTemplate;
}
@Bean
@Override
public CacheResolver cacheResolver() {
return new SimpleCacheResolver(cacheManager());
}
@Bean
@Override
public CacheErrorHandler errorHandler() {
// 用于捕获从Cache中进行CRUD时的异常的回调处理器。
return new SimpleCacheErrorHandler();
}
@Bean
@Override
public CacheManager cacheManager() {
RedisCacheConfiguration cacheConfiguration =
defaultCacheConfig()
.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build();
}
}