SpringBoot引入Redis

目錄

 

1 準備redis

1.1 docker安裝redis(centos7上安裝)

1.2 啓動redis

2 SpringBoot與緩存

2.1 JSR107緩存規範

2.2 Spring緩存抽象

2.3 概念&緩存註解

3 SpringBoot(2.0.3.RELEASE)+Redis項目測試準備

3.1 主要pom依賴

3.2 yml文件配置

3.3 數據庫測試表

4 Redis測試

4.1 @Cacheable註解

4.2 @CachePut註解

4.3 @CacheEvict註解

4.4 @Caching註解

5 SpringBoot Redis緩存序列化處理

6 總結


1 準備redis

1.1 docker安裝redis(centos7上安裝)

docker pull redis

查看鏡像是否下載成功:docker images

1.2 啓動redis

docker run -d -p 6379:6379 --name myredis docker.io/redis

-d:表示後臺啓動

-p:表示端口,6379:6379表示將 虛擬機的6379端口映射爲容器的6379端口

--name myredis  docker.io/redis:命名,將要啓動的docker.io/redis命名爲myredis

查看是否啓動成功:docker ps

2 SpringBoot與緩存

2.1 JSR107緩存規範

Java Caching定義了5個核心接口,分別是CachingProvider、CacheManager、Cache、Entry、Expiry。 
a)CachingProvider定義了創建、配置、獲取、管理和控制多個CacheManager。一個應用可以在運行期訪問多個CachingProvider。 
b)CacheManager定義了創建、配置、獲取、管理和控制多個唯一命名的Cache,這些Cache存在於CacheManager的上下文中。一個CacheManager僅被一個CachingProvider所擁有。
c)Cache是一個類似Map的數據結構並臨時存儲以Key爲索引的值。一個Cache僅被一個CacheManager所擁有。

d)Entry是一個存儲在Cache中的key-value對。
e)Expiry 每一個存儲在Cache中的條目有一個定義的有效期。一旦超過這個時間,條目爲過期的狀態。一旦過期,條目將不可訪問、更新和刪除。緩存有效期可以通過ExpiryPolicy設置。

2.2 Spring緩存抽象

Spring從3.1開始定義了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口來統一不同的緩存技術;並支持使用JCache(JSR-107)註解簡化開發。

Cache接口爲緩存的組件規範定義,包含緩存的各種操作集合。
Cache接口下Spring提供了各種xxxCache的實現;如RedisCache、EhCacheCache 、JCacheCache、ConcurrentMapCache...

每次調用需要緩存功能的方法時,Spring會檢查檢查指定參數的指定的目標方法是否已經被調用過;如果有就直接從緩存中獲取方法調用後的結果,如果沒有就調用方法並緩存結果後返回給用戶,下次調用直接從緩存中獲取。
使用Spring緩存抽象時我們需要關注兩點:確定方法需要被緩存以及他們的緩存策略、從緩存中讀取之前緩存存儲的數據。

2.3 概念&緩存註解

Cache:緩存接口,定義緩存操作,實現有RedisCache、EhCacheCache、JCacheCache、ConcurrentMapCache等。

CacheManager:緩存管理器,管理各種緩存組件。

keyGenerator:緩存數據時key的生成策略。

serialize:緩存數據時value序列化策略。

@EnableCaching:開啓基於註解的緩存。

@CacheConfig:可以抽取緩存公共配置,標註在類上。

@Cacheable:主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存。

@CachePut:保證方法被調用,又希望結果被緩存。(更新操作)

@CacheEvict:清空緩存。(刪除操作)

@Caching:組合註解,可根據需要配置多個@Cacheable、@CachePut、@CacheEvict註解。

@Cacheable/@CachePut/@CacheEvict主要的參數如下:

3 SpringBoot(2.0.3.RELEASE)+Redis項目測試準備

3.1 主要pom依賴

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--數據庫相關-->
        <!--mybatis-spring-boot-starter,mybatis依賴-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

3.2 yml文件配置

spring:
  redis:
    host: 192.168.219.141 # redis服務器地址
    port: 6379 # 默認端口就是6379 可不配置
    #password: root # redis服務器連接密碼(默認爲空)
    database: 0 #使用Redis0號庫
    jedis:
      pool:
        max-active: 8 # 連接池最大連接數(如果配置爲<=0,則沒有限制)
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/spring_cache?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
mybatis:
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    com:
      cache:
        mapper: DEBUG



3.3 數據庫測試表

CREATE TABLE `employee` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `lastName` VARCHAR(255) DEFAULT NULL,
  `email` VARCHAR(255) DEFAULT NULL,
  `gender` INT(2) DEFAULT NULL,
  `d_id` INT(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

三條測試數據:

4 Redis測試

4.1 @Cacheable註解

     @Cacheable(cacheNames = "emp", key = "#id")
    // @Cacheable(cacheNames = "emp", key = "#id",condition = "#id > 1")
    //@Cacheable(cacheNames = "emp", key = "#id",unless = "#result == null")
    public Employee getEmp(Integer id) {
        System.out.println("查詢" + id + "號員工");
        return employeeMapper.getEmpById(id);
    }
說明:
@Cacheable(cacheNames = "emp", key = "#id"):
    將查詢到的Employee存入緩存,key就是傳入的id。
@Cacheable(cacheNames = "emp", key = "#id",condition = "#id > 1"):
    condition爲緩存的條件,當condition 判斷爲true時,緩存結果,即當員工的id大於1時,纔會緩存對應的結果。condition在方法執行之前之後都可以進行判斷。
@Cacheable(cacheNames = "emp", key = "#id",unless = "#result == null"):
    unless用於否決緩存,只有當條件爲false時纔會緩存。並且,該表達式只在方法執行之後判斷。經過測試,默認就算不設置unless 條件,結果爲null也是不允許緩存的。

4.2 @CachePut註解

    @CachePut(value = "emp", key = "#result.id") //返回結果中的ID
    // @CachePut(value = "emp",key="#employee.id") //參數中的ID
    public Employee updateEmp(Employee employee) {
        System.out.println("employee:" + employee);
        employeeMapper.update(employee);
        return employeeMapper.getEmpById(employee.getId());
    }

說明:

第一種方式,將結果中的ID作爲key。先緩存3號員工信息,窄將3號員工Eric的lastname改爲Andy,以下分別爲更新前和更新後的緩存。

 

第二種方式是將參數中的ID作爲key,測試發現最終的效果是一樣的,更新員工後,緩存也更新了。

4.3 @CacheEvict註解

    // key 清除指定的數據
    // beforeInvocation默認爲false,方法執行之後再刪除緩存;
    //  beforeInvocation爲true:方法執行之前刪除緩存,不管方法成不成功
    @CacheEvict(value = "emp", key = "#id",beforeInvocation = false)
    //allEntries默認爲false,當爲true,那麼emp緩存全部刪除
    // @CacheEvict(value = "emp",allEntries = true,beforeInvocation = false)
    public Integer deleteEmp(Integer id) {
        Integer result = employeeMapper.deleEmpById(id);
        System.out.println("刪除" + id + "號員工");
        return result;
    }

說明:

@CacheEvict主要就是兩個配置比較重要。 beforeInvocation默認爲false,方法執行之後再刪除緩存;beforeInvocation爲true,方法執行之前刪除緩存,不管方法成不成功。
 allEntries默認爲false,當爲true,那麼對應的緩存全部刪除。

4.4 @Caching註解

   // 組合註解
    @Caching(
            cacheable = {
                    @Cacheable(value = "emp", key = "#lastName")
            },
            put = {
                    @CachePut(value = "emp", key = "#result.id"),
                    @CachePut(value = "emp", key = "#result.email")
            }
    )
    public Employee getEmpByLastname(String lastName) {

        Employee employee = employeeMapper.getByLastname(lastName);
        System.out.println("通過lastname查詢");
        return employee;
    }

說明:

@Caching源碼如下:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {
    Cacheable[] cacheable() default {};

    CachePut[] put() default {};

    CacheEvict[] evict() default {};
}

@Caching是個組合註解,可以通過這個註解來配置不同的緩存,比如示例代碼中,通過lastname查詢,可以根據查詢結果設置不同的緩存,也可以根據查詢結果更新緩存,按自己的需要進行組合配置。

通過lastname=Andy查詢,通過結果可以發現@Caching生效了。

5 SpringBoot Redis緩存序列化處理

SpringBoot RedisTemplate是用來操作key-value對象類型,默認採用JDK序列化類型。JDK序列化性能差,而且數據是以二進制的形式(如下圖所示)存儲在Redis服務端,不便於查詢,同時對象還需要實現Serializable接口。

如果要直接查看緩存數據,會比較困難,我們更希望數據以json的形式存儲。

RedisSerializer有很多種實現,默認是使用的Jdk序列化方式,那麼可以通過使用Jackson2JsonRedisSerializer來實現新的序列化。

更改默認的序列化器:

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheManager redisCacheManager =
                RedisCacheManager.builder(redisConnectionFactory)
                        .cacheDefaults(defaultCacheConfig(10000))
                        .withInitialCacheConfigurations(initCacheConfigMap())
                        .transactionAware()
                        .build();
        return redisCacheManager;
    }

    private RedisCacheConfiguration defaultCacheConfig(Integer second) {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer
                = new Jackson2JsonRedisSerializer<Object>(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        RedisCacheConfiguration redisCacheConfiguration
                = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(second))
                .serializeKeysWith(RedisSerializationContext
                        .SerializationPair
                        .fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext
                        .SerializationPair
                        .fromSerializer(jackson2JsonRedisSerializer)
                ).disableCachingNullValues();
        return redisCacheConfiguration;
    }
    // 不同緩存的過期時間,可以自定義配置
    private Map<String, RedisCacheConfiguration> initCacheConfigMap() {
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>();

        // 自己按需配置
        configMap.put("User", this.defaultCacheConfig(1000));
        configMap.put("User1", this.defaultCacheConfig(1000));
        configMap.put("User2", this.defaultCacheConfig(1000));
        configMap.put("User3", this.defaultCacheConfig(1000));

        return configMap;
    }
}

6 總結

堅持寫博客!堅持寫博客!堅持寫博客!(其實已經很久沒有寫了)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章