之前已经讲了redis的简单介绍和在程序中的简单使用,这篇我们讲一下使用Annotation缓存数据
之前我们讲了手动操作redis进行存取操作,在真实的业务场景中,我们并不想这样去使用,而是把Redis当做一种缓存来使用,把service或者dao层的数据进行缓存, 最简单的方式就是通过注解。在SpringBoot中使用Redis做缓存也非常简单,只需要在pom中引入spring-boot-starter-cache即可。
Spring缓存的常用注解
@CacheConfig:主要用于配置该类中会用到的一些共用的缓存配置。在这里@CacheConfig(cacheNames = “users”):配置了该数据访问对象中返回的内容将存储于名为users的缓存对象中,我们也可以不使用该注解,直接通过@Cacheable自己配置缓存集的名字来定义。
@Cacheable:配置了findByName函数的返回值将被加入缓存。同时在查询时,会先从缓存中获取,若不存在才再发起对数据库的访问。该注解主要有下面几个参数:
- value、cacheNames:两个等同的参数(cacheNames为Spring4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了 。
- key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:
@Cacheable(key = “#p0”);
使用函数第一个参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考官方文档 - condition:缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:
@Cacheable(key = “#p0”, condition = “#p0.length() < 3”);
表示只有当第一个参数的长度小于3的时候才会被缓存,若做此配置上面的AAA用户就不会被缓存,读者可自行实验尝试。 - unless:另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。
- keyGenerator:用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现
org.springframework.cache.interceptor.KeyGenerator
接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的 - cacheManager:用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
- cacheResolver:用于指定使用那个缓存解析器,非必需。需通过
org.springframework.cache.interceptor.CacheResolver
接口来实现自己的缓存解析器,并用该参数指定。
@CachePut:配置于函数上,能够根据参数定义条件来进行缓存,它与@Cacheable不同的是,它每次都会真实调用函数,所以主要用于数据新增和修改操作上。它的参数与@Cacheable类似,具体功能可参考上面对@Cacheable参数的解析。
@CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除相应数据。除了同@Cacheable一样的参数之外,它还有下面两个参数:
- allEntries:非必需,默认为false。当为true时,会移除所有数据
- beforeInvocation:非必需,默认为false,会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。
下面,我们来模拟数据库的操作,并把结果缓存到Redis中
@Service
@Slf4j
@CacheConfig(cacheNames = "users")
public class RedisCacheServiceImpl implements RedisCacheService {
@Override
@CachePut(key = "#p0.id")
public User save(User user) {
log.info("-----执行数据库更新操作");
log.info("-----数据库更新完成,返回结果");
return user;
}
@Override
@Cacheable(key = "#p0")
public User get(String id) {
log.info("-----执行数据库查询操作");
User user = User.builder().id(id).name("spring").age(18).build();
log.info("-----数据库查询完成,返回结果");
return user;
}
@Override
@CacheEvict(key = "#p0")
public void delete(String id) {
log.info("-----执行数据库删除操作");
log.info("-----数据库删除完成,返回结果");
}
}
在Junit中进行测试
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
@Slf4j
public class RedisCacheServiceTest {
@Resource
private RedisCacheService redisCacheService;
@Test
public void testGet() {
User user = redisCacheService.get("1111111");
log.info(user.toString());
}
@Test
public void testSave() {
User user = User.builder().id("1111111").name("spring").age(20).build();
redisCacheService.save(user);
}
@Test
public void testDelete() {
redisCacheService.delete("1111111");
}
}
先调用get方法,此时,Redis中没有此数据,会进入方法,拿到数据之后返回,并且把数据缓存到Redis中,结果如下:
2019-05-22 10:57:57.532 INFO 42313 --- [ main] o.b.r.s.impl.RedisCacheServiceImpl : -----执行数据库查询操作
2019-07-29 10:57:57.533 INFO 42313 --- [ main] o.b.r.s.impl.RedisCacheServiceImpl : -----数据库查询完成,返回结果
2019-07-29 10:57:57.557 INFO 42313 --- [ main] o.b.redis.service.RedisCacheServiceTest : User(id=1111111, name=spring, age=18)
再调用一次get方法,此时将不会进入方法中,直接从缓存中拿到数据并返回,结果如下:
2019-07-29 10:57:57.557 INFO 42313 --- [ main] o.b.redis.service.RedisCacheServiceTest : User(id=1111111, name=spring, age=18)
再调用save方法,会把缓存中ID为1111111的User年龄更新为20,调用delete方法会删除缓存,和预期的结果一致,这里就不贴结果了,感兴趣的同学可以自行验证。redis的学习到这里暂时结束,以后用到更深入的技术再来进行探讨研究。
摘自:https://blog.csdn.net/oppo5630/article/details/80403111