为什么要用缓存?这里不做过多解释,不管是移动端还是前端,我们都有接触过!Redis,是一个轻量级的key-value数据库,就类似于安卓端的SP,或者前端的localStorage,就是把要缓存的数据放入键值对,用的时候即可通过key取出value,直接缓存获取,从而不再需要再次调用接口或者查询数据库获取,这样理解,你就会觉得简单多了!
项目下载地址:
GitHub:https://github.com/baiyuliang/SpringBoot
pom.xml引入:
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
application.yml添加redis配置:
spring:
redis:
host: 39.xxx.x.xx
port: 6379
database: 1 # redis16库中的哪一库,默认0
client-name: redis
password: 123456
timeout: 3000 # 连接超时时间(毫秒)
jedis.pool.max-active: 8 #redis的连接池最大连接数
jedis.pool.max-idle: 8 #redis的连接池中最大连接空闲数
jedis.pool.max-wait: -1 #redis的连接池中最大等待时间,-1,表示没有限制
jedis.pool.min-idle: 0 #redis的连接池中最小连接空闲数
创建RedisConfig:
package com.byl.springboottest.config;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
template.setDefaultSerializer(serializer);
return template;
}
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(1))
.disableCachingNullValues()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(cacheConfiguration).build();
}
}
开始测试:
1.启用缓存@EnableCaching:Application入口:
@EnableCaching//启用缓存
@SpringBootApplication
public class SpringboottestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringboottestApplication.class, args);
}
}
2.在Service的某方法上添加注解@Cacheable:
@Service
public class UserServiceImpl implements UserService {
@Resource
UserRepository userRepository;
@Cacheable(cacheNames = "user", condition = "#id>0", unless = "#result==null")
@Override
public User getUserById(Integer id) {
return userRepository.getOne(id);
}
@Override
public User getUserByName(String username) {
return userRepository.findByUserName(username);
}
}
cacheNames 缓存名,condition 缓存条件(只有id>0的才缓存),unless也是缓存条件,但他表示的是非关系,也即时,满足条件了不缓存!
运行项目,浏览器输入:http://localhost:8080/byl/user/2,来测试对应方法的缓存情况:
第一次运行结果:
控制台:
表明第一次是从数据库查询的无误!查看Redis数据库:
缓存成功!我换一个浏览器,再次运行:
此时控制台并没有打印任何Sql数据,表明Redis已经整合成功!
当需要更新缓存时,我们可以在某一方法上加上@CachePut,删除缓存则用@CacheEvict!
在使用@Cacheable时要先声明cacheNames,可以这么理解,就是给你的缓存信息划分模块,与其他缓存信息互不影响,你可以把同一类业务划分到统一模块,比如例子中的user,缓存到Redis后即可在user下查询相关信息:
指定其它名称,就会生成对应的“文件夹”!
user::2,user是自动添加的字段,2就是key,因为如果我们不指定key,那么缓存会自动将参数值作为key键存入,我们可以用keyGenerator属性自定义key生成机制,但要注意的是,存入的key值要有一定的规律,那么你在更新或删除缓存时,才能准确的通过对应的key操作缓存数据!
以下是一个自定义keyGenerator的例子:
@Configuration
public class MyCacheConfig {
@Bean("myKeyGenerator")
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
return method.getName() + "[" + Arrays.asList(objects).toString() + "]";
}
};
}
}
将方法名和参数作为key!
引用该keyGenerator:
@Cacheable(cacheNames = "user", condition = "#id>0", unless = "#result==null" ,keyGenerator = "myKeyGenerator")
如果我们直接在方法上声明@Cacheable,会默认把方法返回结果给缓存起来,而在实际开发中,我们在Service层中,方法的返回结果往往带有固定格式的数据模型,如:
{
code:1,
msg:"获取列表成功",
data:{
total:1,
list:[{
...
}]
}
}
这可能并不符合我们的实际需求,因为我们只想对从数据库查出来的数据进行缓存,而不想对业务层返回的数据进行缓存,此时,我们就可以直接用代码的方式进行缓存数据存取了:
@Resource
RedisCacheManager redisCacheManager;//缓存管理器
// @Cacheable(cacheNames = "user",condition = "#id>0", unless = "#result==null")
@Override
public User getUserById(Integer id) {
User user;
Cache cache = redisCacheManager.getCache("user");//cacheNames
if (cache.get("getUserById" + id) != null) {
user = (User) cache.get("getUserById" + id).get();//通过key获取value
if (user != null) {
System.out.println("从缓存中获取到结果>>" + user.getNickName());
return user;
}
}
user = userRepository.findById(id).get();
cache.put("getUserById" + id, user);//缓存数据
return user;
}
我们先清空redis数据库,然后运行项目,浏览器输入:http://localhost:8080/byl/user/2
查看redis数据库:
再次刷新浏览器:
当然,cache还有n多种方法,在合适的时候选择使用: