Spring Boot教程(二)使用Redis作集中式缓存

准备工做

能够下载案例Chapter4-4-1,进行下面改造步骤。html

先来回顾一下在此案例中,咱们作了什么内容:git

  • 引入了spring-data-jpaEhCache
  • 定义了User实体,包含idnameage字段
  • 使用spring-data-jpa实现了对User对象的数据访问接口UserRepository
  • 使用Cache相关注解配置了缓存
  • 单元测试,经过连续的查询和更新数据后的查询来验证缓存是否生效

开始改造

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

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-redis</artifactId>
    </dependency>

     

  • application.properties中增长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。app

    问题思考

    为何一样的逻辑在EhCache中没有问题,可是到Redis中会出现这个问题呢?框架

    在EhCache缓存时没有问题,主要是因为EhCache是进程内的缓存框架,第一次经过select查询出的结果被加入到EhCache缓存中,第二次查询从EhCache取出的对象与第一次查询对象其实是同一个对象(能够在使用Chapter4-4-1工程中,观察u1==u2来看看是不是同一个对象),所以咱们在更新age的时候,实际已经更新了EhCache中的缓存对象。spring-boot

    而Redis的缓存独立存在于咱们的Spring应用以外,咱们对数据库中数据作了更新操做以后,没有通知Redis去更新相应的内容,所以咱们取到了缓存中未修改的数据,致使了数据库与缓存中数据的不一致。单元测试

    所以咱们在使用缓存的时候,要注意缓存的生命周期,利用好上一篇上提到的几个注解来作好缓存的更新、删除

    进一步修改

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

    @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中获取了。

  •  

    源码来源

    本文内容到此为止,主要介绍了为何要使用Redis作缓存,以及如何在Spring Boot中使用Redis作缓存,而且经过一个小问题来帮助你们理解缓存机制,在使用过程当中,必定要注意缓存生命周期的控制,防止数据不一致的状况出现。
相关文章
相关标签/搜索