springboot【16】缓存之Redis

下面以上一篇的例子作为基础进行改造,将缓存内容迁移到redis中。

注意:在使用redis缓存过程中,一定要注意缓存生命周期的控制,防止数据不一致的情况出现。


开始改造

  • 删除EhCache的配置文件src/main/resources/ehcache.xml

  • pom.xml中删除EhCache的依赖,增加redis的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-redis</artifactId>
</dependency>
  • application.properties中增加redis配置,以本地运行为例,比如:
#redis
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1

我们需要做的配置到这里就已经完成了,Spring Boot会在侦测到存在Redis的依赖并且Redis的配置是可用的情况下,使用RedisCacheManager初始化CacheManager

为此,我们可以单步运行我们的单元测试,可以观察到此时CacheManager的实例是org.springframework.data.redis.cache.RedisCacheManager,并获得下面的执行结果:

Hibernate: insert into user (age, name) values (?, ?)
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第一次查询:10
第二次查询:10
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: update user set age=?, name=? where id=?
第三次查询:10

可以观察到,在第一次查询的时候,执行了select语句;第二次查询没有执行select语句,说明是从缓存中获得了结果;而第三次查询,我们获得了一个错误的结果,根据我们的测试逻辑,在查询之前我们已经将age更新为20,但是我们从缓存中获取到的age还是为10。为什么同样的逻辑在EhCache中没有问题,但是到Redis中会出现这个问题呢?

在EhCache缓存时没有问题,主要是由于EhCache是进程内的缓存框架,第一次通过select查询出的结果被加入到EhCache缓存中,第二次查询从EhCache取出的对象与第一次查询对象实际上是同一个对象(可以在使用example15工程中,观察u1==u2来看看是否是同一个对象),因此我们在更新age的时候,实际已经更新了EhCache中的缓存对象。而Redis的缓存独立存在于我们的Spring应用之外,我们对数据库中数据做了更新操作之后,没有通知Redis去更新相应的内容,因此我们取到了缓存中未修改的数据,导致了数据库与缓存中数据的不一致。因此我们在使用缓存的时候,要注意缓存的生命周期,利用好上一篇上提到的几个注解来做好缓存的更新、删除。



进一步修改


针对上面的问题,我们只需要在更新age的时候,通过@CachePut来让数据更新操作同步到缓存中,就像下面这样:

package com.lyd.domain;


import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.jpa.repository.JpaRepository;

@CacheConfig(cacheNames = "users")
public interface UserRepository extends JpaRepository<User, Long>{

	@Cacheable(key = "#p0")
	User findByName(String name);
	
	@CachePut(key = "#p0.name")
	User save(User user);
}

在redis-cli中flushdb,清空一下之前的缓存内容,再执行单元测试,可以获得下面的结果:

Hibernate: insert into user (age, name) values (?, ?)
第一次查询:10
第二次查询:10
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: update user set age=?, name=? where id=?
第三次查询:20

可以看到,我们的第三次查询获得了正确的结果!同时,我们的第一次查询也不是通过select查询获得的,因为在初始化数据的时候,调用save方法时,就已经将这条数据加入了redis缓存中,因此后续的查询就直接从redis中获取了。


下面是完整项目结构:



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值