java中使用redis


java中使用redis

 

redis 客戶端操作工具:

Jedis   api 在線網址:http://tool.oschina.net/uploads/apidocs/redis/clients/jedis/Jedis.html

redisson  官網地址:https://redisson.org/

redisson  git項目地址:https://github.com/redisson/redisson

lettuce  官網地址:https://lettuce.io/

lettuce  git項目地址:https://github.com/lettuce-io/lettuce-core

 

概念:

  Jedis:是Redis的Java實現客戶端,提供了比較全面的Redis命令的支持,

  Redisson:實現了分布式和可擴展的Java數據結構。

  Lettuce:高級Redis客戶端,用於線程安全同步,異步和響應使用,支持集群,Sentinel,管道和編碼器。

優點:

  Jedis:比較全面的提供了Redis的操作特性

  Redisson:促使使用者對Redis的關注分離,提供很多分布式相關操作服務,例如,分布式鎖,分布式集合,可通過Redis支持延遲隊列

  Lettuce:主要在一些分布式緩存框架上使用比較多

可伸縮:

Jedis:使用阻塞的I/O,且其方法調用都是同步的,程序流需要等到sockets處理完I/O才能執行,不支持異步。Jedis客戶端實例不是線程安全的,所以需要通過連接池來使用Jedis。

Redisson:基於Netty框架的事件驅動的通信層,其方法調用是異步的。Redisson的API是線程安全的,所以可以操作單個Redisson連接來完成各種操作

Lettuce:基於Netty框架的事件驅動的通信層,其方法調用是異步的。Lettuce的API是線程安全的,所以可以操作單個Lettuce連接來完成各種操作

 

1 maven依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <!--<version>2.1.4.RELEASE</version>-->
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>

 

2、yml:

spring:
  redis:
    database: 0 # Redis數據庫索引(默認為0)
    host: 192.168.0.110 # Redis服務器地址
    port: 6379 # Redis服務器連接端口
    password: 123456 # Redis服務器連接密碼(默認為空)
    timeout: 5000ms # 連接超時時間(毫秒)默認是2000ms
    lettuce:
      pool:
        max-active: 200 # 連接池最大連接數(使用負值表示沒有限制)
        max-idle: 20 # 連接池中的最大空閑連接
        min-idle: 0 # 連接池中的最小空閑連接
        max-wait: -1ms # 連接池最大阻塞等待時間(使用負值表示沒有限制)
    #sentinel:
      #master: mymaster #哨兵監聽的master名稱
      #nodes: 192.168.203.205:26479, 192.168.203.205:26480 #哨兵地址列表,多個以,分割
#    cluster:
#      max-redirects: 3
#      nodes: 192.168.0.201:7001,192.168.0.201:7002,192.168.0.201:7003,192.168.0.201:7004,192.168.0.201:7005,192.168.0.201:7006

 

配置RestTemplate 的序列化方式,默認使用jdk提供的序列化方式,不可讀,配置自己的序列化方式 :

@Configuration
@EnableCaching //支持緩存注解
public class MyRedisConfig extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());                    // key序列化
        redisTemplate.setValueSerializer(new FastJsonRedisSerializer<>(Object.class));     // value序列化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());                // Hash key序列化
        redisTemplate.setHashValueSerializer(new StringRedisSerializer()); // Hash value序列化
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }
    
}

 RedisTemplate操作Redis  Api 請參考: https://www.cnblogs.com/dw3306/p/12840012.html

 

 springboot + spring cache + redis 實現緩存

spring cache 是spring3版本之后引入的一項技術,可以簡化對於緩存層的操作,spring cache與springcloud stream類似,都是基於抽象層,可以任意切換其實現。其核心是CacheManagerCache這兩個接口,所有由spring整合的cache都要實現這兩個接口、Redis的實現類則是 RedisCache 和 RedisManager。

 1. 首先認識幾個用到的名稱及注解

@EnableCaching 開啟基於注解的緩存,寫在啟動類上,這個注解會被spring發現,並且會創建一個切面(aspect) 並觸發Spring緩存注解的切點(pointcut) 。 根據所使用的注解以及緩存的狀態, 這個切面會從緩存中獲取數據, 將數據添加到緩存之中或者從緩存中移除某個值。
@Cacheable 標注在方法上,如果該方法結果存在緩存則使用緩存,否則執行方法並將結果緩存
@CacheEvict 清除緩存
@CachePut 不管有沒有緩存都要執行方法,且把結果緩存,如果存在緩存就更新
Cache 緩存接口,定義緩存操作
CacheManager 緩存管理器,管理各種緩存組件
keyGenerator 緩存數據時key的生成策略
serialize 緩存數據時,value的序列化策略

 

當然,緩存管理器除了RedisCacheManager還有一些其他的。例如

 

  1. SimpleCacheManager
  2. NoOpCacheManager
  3. ConcurrentMapCacheManager
  4. CompositeCacheManager
  5. EhCacheCacheManager

 

默認緩存管理器:ConcurrentMapCacheManager,這個簡單的緩存管理器使用java.util.concurrent.ConcurrentHashMap作為其緩存存儲

@Cacheable屬性講解

@Cacheable 是一個既可以應用於方法級別,也可用於類級別的注解。自spring3.1開始就通過它實現了緩存管理。

 

@Cacheable能干什么?
為了通俗易懂的理解,舉個栗子:一個方法,getBooksByUsernameAndLanguage(String username, int language),顯然,是一個獲取數據庫里所有我的英文書對象的方法,返回應該是一個列表。如果這個函數的返回值很大,而且會在頁面上被經常調用,那么每一次調用都要重新連接數據庫並返回一個數據量龐大的list,可能頁面響應和資源占用會比較大。而我們希望的是,第一次調用這個方法時,返回的數據能被放到服務器端的緩存里,以便於后面要調用這個方法時,能直接從緩存里取到,這樣就不用再查數據庫占用資源了。而@Cacheable的作用就是這個。
@Cacheable怎么用?
@Cacheable(value = "CACHE_BOOK",key = "#username", condition = "#language = 1")
public List<Book> getBooksByUsernameAndLanguage(String username, int language) {
     // balabalabala...里面的代碼不重要
     return bookList;
}
  • value : 必須要的。就是個自己取的名字,通過它指明了第一次調用這個方法時返回的bookList將被存在內存的哪里。
  • key : 可選。要使用SpEL表達式,這里與參數username對應,當傳入的username值變了的話就不去取緩存里的數據了,而是執行getBooksByUsernameAndLanguage方法。(這是必須的,因為username變了,返回值也就變了,緩存里的數據不符合了,因此這個選項很重要)。spring默認用方法的簽名來當做key。
  • condition:方法返回的結果bookList,要不要緩存起來?condition就添加了一個限定條件。這個例子中,只有傳入的語言代碼是1,返回的bookList才會被緩存起來,如果給language傳了別的值,那么bookList是不會緩存起來的。

 @Cacheable注解中參數詳情見下表:

參數名 作用
cacheNames  被緩存的時候的命名空間
key 這里的key的優先級是最高的,可以覆蓋掉全局配置的key,如果不配置的話使用的就是全局的key
keyGenerator  指定的緩存的key的生成器,默認沒有
cacheManager  指定要使用哪個緩存管理器。默認是底層自動配置的管理器
condition 滿足什么條件會進行緩存,里面可以寫簡單的表達式進行邏輯判斷
unless 滿足什么條件不進行緩存,里面可以寫簡單的表達式進行邏輯判斷
sync 加入緩存的這個操作是否是同步的
value
指定將方法的返回結果放在哪個緩存中,可以指定多個,用大括號保存

@CacheEvict簡單屬性講解
@CacheEvict 的參數信息見下表:
參數名 描述
allEntries 是否刪除該命名空間下面的全部緩存,默認是false
beforeInvocation 在執行刪除方法前就執行清空緩存操作,默認是false,如果刪除方法執行報錯該注解則不執行
@CacheConfig簡化注解配置

標注在類上,類中方法就不需要再指定該注解說配置好的屬性

在controller或者service的類上面添加 @CacheConfig ,注解里面的參數詳情見下表:

參數名 參數值 作用
cacheNames 可以隨意填寫,一般是一個模塊或者一個很重要的功能名稱 無具體作用,只是用來區分緩存,方便管理
keyGenerator 就是自己配置的KeyGenerator的名稱 全局key都會以他的策略去生成
cacheManager 自己配置的CacheManager 用來操作Cache對象的,很多對於緩存的配置也由他去管理

在標有@CacheConfig的類里面編寫一個查詢單個對象的方法並添加 @Cacheable注解

 eg: 

@Cacheable(key = "#id", unless = "#result == null") 
@PatchMapping("/course/{id}")
public Course courseInfo(@PathVariable Integer id) {
    log.info("進來了 .. ");
    return courseService.getCourseInfo(id);
}

 #result是代表函數的返回值

cache 配置:

在上面的  MyRedisConfig 中添加如下配置:

  /**
     * key的生成策略的配置: 類名+方法名+參數列表的類型+參數值 再做 哈希散列 作為key
     *
     * @return
     */
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        log.info("RedisCacheConfig.keyGenerator()");
        return new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... objects) {
                StringBuilder sb = new StringBuilder();
                sb.append(o.getClass().getSimpleName())
                        .append(":")
                        .append(method.getName())
                        .append(":");
                for (Object obj : objects) {
                    if (null != obj) {// 替換字符串
                        String objKey = JSON.toJSONString(obj);
                        objKey = objKey.replace(":", "=");
                        sb.append(objKey);
                    }
                }
                return sb.toString();
            }
        };
    }


    //緩存生存時間
    private Duration timeToLive = Duration.ofHours(1);

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        //redis緩存配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                //緩存生存時間
                .entryTtl(this.timeToLive)
                // 配置序列化(解決亂碼的問題)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new FastJsonRedisSerializer<>(Object.class)))
                // 不緩存空值
                .disableCachingNullValues();
        //根據redis緩存配置和reid連接工廠生成redis緩存管理器
        RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(config)
                .build();
        log.debug("自定義RedisCacheManager加載完成");
        return redisCacheManager;
    }

    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

啟動類上添加: @EnableCaching //支持緩存注解

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM