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作緩存,而且經過一個小問題來幫助你們理解緩存機制,在使用過程當中,必定要注意緩存生命週期的控制,防止數據不一致的狀況出現。
相關文章
相關標籤/搜索