一. pom.xm文件引入對應jar包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
二. application.yml引入redis服務端配置
# redis相關配置 redis: host: 192.168.80.3 port: 6379 database: 0 timeout: 60s # 數據庫連接超時時間,springboot2.0 中該參數的類型為Duration,這里在配置的時候需要指明單位 # 連接池配置,springboot2.0中直接使用jedis或者lettuce配置連接池 jedis: pool: # 最大空閑連接數 max-idle: 500 # 最小空閑連接數 min-idle: 50 # 等待可用連接的最大時間,負數為不限制 max-wait: -1s # 最大活躍連接數,負數為不限制 max-active: -1
說明:Jedis和Lettuce的比較:
Jedis :
直連模式,在多個線程間共享一個 Jedis 實例時是線程不安全的,如果想要在多線程環境下使用 Jedis,需要使用連接池,
每個線程都去拿自己的 Jedis 實例,當連接數量增多時,物理連接成本較高。
Lettuce:
連接是基於Netty的,連接實例可以在多個線程間共享,
所以,一個多線程的應用可以使用同一個連接實例,而不用擔心並發線程的數量。當然這個也是可伸縮的設計,一個連接實例不夠的情況也可以按需增加連接實例。
通過異步的方式可以讓我們更好的利用系統資源,而不用浪費線程等待網絡或磁盤I/O。
三.RedisConfig 配置RedisTemplate和CacheManage
package com.luckydan.springboot.config; import java.time.Duration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @package: com.luckydan.springboot.config * @description: redis配置文件 * @author: gl * @date: 2018年11月23日 * @version: 1.0.0 */ @EnableCaching @Configuration public class RedisConfig extends CachingConfigurerSupport { @Bean(name="redisTemplate") public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<Object>(Object.class); // value值的序列化采用fastJsonRedisSerializer template.setValueSerializer(serializer); template.setHashValueSerializer(serializer); // key的序列化采用StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { // 生成一個默認配置,通過config對象即可對緩存進行自定義配置 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 設置緩存的默認過期時間,也是使用Duration設置 config = config.entryTtl(Duration.ofMinutes(1)) .disableCachingNullValues(); // 不緩存空值 // 設置一個初始化的緩存空間set集合 Set<String> cacheNames = new HashSet<>(); cacheNames.add("my-redis-cache1"); cacheNames.add("my-redis-cache2"); // 對每個緩存空間應用不同的配置 Map<String, RedisCacheConfiguration> configMap = new HashMap<>(); configMap.put("my-redis-cache1", config); configMap.put("my-redis-cache2", config.entryTtl(Duration.ofSeconds(120))); // 使用自定義的緩存配置初始化一個cacheManager RedisCacheManager cacheManager = RedisCacheManager.builder(factory) .initialCacheNames(cacheNames) // 注意這兩句的調用順序,一定要先調用該方法設置初始化的緩存名,再初始化相關的配置 .withInitialCacheConfigurations(configMap) .build(); return cacheManager; } }
說明:在獲取RedisTemplate過程中需要對key-value鍵值對分別進行序列化操作,可以使用Springboot自帶的Jackson2JsonRedisSerializer進行序列化,也可以使用fastjson進行自定義序列化
自定義序列化:略
四.整合Redis需要使用的注解介紹:
1.@Cacheable 可以標記在方法上,也可以標記在類上。當標記在方法上時表示該方法是支持緩存的,當標記在類上時則表示該類所有的方法都是支持緩存的。應用到讀取數據的方法上,將先從緩存中讀取該方法的返回值,如果沒
有再從DB獲取數據,然后把數據添加到緩存中
緩存是以鍵值對進行的,值就是方法的返回結果,至於鍵的話,Spring又支持兩種策略,默認策略和自定義策略,需要注意的是當一個支持緩存的方法在對象內部被調用時是不會觸發緩存功能的
。
屬性值:value,key,condition(參考注解@CacheEvcit的屬性值),unless
參數 | 解釋 | example |
unless | 緩存條件:判斷unless,如果返回false,則放入緩存(與Condition相反 )
|
@CachePut (value="user", key="#root.method.name_+#userId" unless="#username eq han") |
condition | 緩存的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進行緩存 @Cacheable 將在執行方法之前( #result還拿不到返回值)判斷condition,如果返回true, 則查緩存; @CachePut 將在執行完方法后(#result就能拿到返回值了)判斷condition,如果返回true, 則放入緩存; @CacheEvcit 當beforeInvocation= false 表示在方法執行之后調用(#result就能拿到返 回值了)且判斷condition,如果返回true,則移除緩存。 |
@CacheEvict (value="user", condition=”#userName.length()>2”) |
2.@CacheEvcit 應用到刪除數據的方法上,調用方法時會從緩存中刪除對應key的數據
屬性值:value,key,condition,allentries,beforeInvocation
參數 | 解釋 | example |
value | 緩存的名稱,在 spring 配置文件中定義, 必須指定至少一個 |
例如: @Cacheable(value=”mycache”) @Cacheable(value={”cache1”,”cache2”} |
key | 緩存的 key,可以為空,如果指定要按照 SpEL 表達式編寫,如果不指定,則缺省 按照方法的所有參數進行組合 |
@CacheEvict (value=”user”,key=”#userName”) |
condition | 緩存的條件,可以為空,使用 SpEL 編寫, 返回 true 或者 false,只有為 true 才進行 緩存 |
@CacheEvict (value=”user”,condition=”#userName.length()>2”) |
allentries | 是否清空所有緩存內容,缺省為 false, 如果指定為 true,則方法調用后將立即清 空所有緩存 |
@CachEvict(value=”user”,allEntries=true) |
beforeInvocation | 是否在方法執行前就清空,缺省為 false, 如果指定為 true,則在方法還沒有執行 的時候就清空緩存,缺省情況下,如果 方法執行拋出異常,則不會清空緩存 |
@CachEvict (value=”user”,beforeInvocation=true) |
3.@CachePut 應用到寫數據的方法上,如新增/修改方法,調用方法時會自動把相應的數據放入緩存,
具體步驟如下:Spring在每次執行前都會檢查Cache中是否存在相同key的緩存元素,如果存在就不再執行該方法,而是直接從緩存中獲取結果進行返回,否則才會執行並將返回結果存入指定的緩存中。
與@Cacheable的區別:執行前不會去檢查緩存中是否存在之前執行過的結果,而是每次都會執行該方法,並將執行結果以鍵值對的形式存入指定的緩存中
屬性值:value,key,condition,unless(參考注解@CacheEvcit的屬性值),unless
4. @CacheConfig 屬於類級別的注解,當方法上的注解未注明value時,以@CacheConfig的value屬性為准,當方法上注明value時,以方法上的注解value屬性為准
5. @Caching 可能組合多個Cache注解使用;比如用戶新增成功后,我們要添加id–>user;username—>user;email—>user的緩存;此時就需要@Caching組合多個注解標簽了
ex:可以使用如下方式使用:
@Caching(put = { @CachePut(value = "user", key = "#user.id"), @CachePut(value = "user", key = "#user.username"), @CachePut(value = "user", key = "#user.email") }) public User save(User user) {}
ex:也可以使用自定義注解的方式實現相應的功能
/** * 自定義注解 */ @Caching(put = { @CachePut(value = "user", key = "#user.id"), @CachePut(value = "user", key = "#user.username"), @CachePut(value = "user", key = "#user.email") }) @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface UserSaveCache { }
將自定義注解添加到指定的方法上:這種方法會使代碼很干凈(強力推薦)
1 @UserSaveCache 2 public User save(User user){}