Mybatis-plus如何開(kāi)啟二級(jí)緩存
一、Ehcache、Redis比較
? ehcache是直接在jvm虛擬機(jī)中緩存,速度快,效率高;但是共享緩存麻煩,在分布式下顯得功能弱;
? redis是通過(guò)socket訪(fǎng)問(wèn)到緩存服務(wù),效率比ehcache低,但是比訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)快;在處理分布式下共享緩存很方便,并且機(jī)制成熟。
? 單體應(yīng)用可以采用ehcache,在大型應(yīng)用場(chǎng)景下,分布式要求就采用redis。
補(bǔ)充:
ehcache也是有共享緩存的方案,但是是通過(guò)RMI或Jgroup多廣播方式進(jìn)行廣播緩存和通知刷新,這樣緩存復(fù)雜,維護(hù)不方便,簡(jiǎn)單緩存還是可以的,但是涉及恢復(fù)或數(shù)據(jù)量大的情況下,顯得功能弱,不適合。
二、Ehcache
1.簡(jiǎn)介
? EhCache 是一個(gè)純Java的進(jìn)程內(nèi)緩存框架,具有快速、精干等特點(diǎn),是Hibernate中默認(rèn)CacheProvider。
Ehcache是一種廣泛使用的開(kāi)源Java分布式緩存。主要面向通用緩存,Java EE和輕量級(jí)容器。
它具有內(nèi)存和磁盤(pán)存儲(chǔ),緩存加載器,緩存擴(kuò)展,緩存異常處理程序,一個(gè)gzip緩存servlet過(guò)濾器,支持REST和SOAP api等特點(diǎn)。
? Spring 提供了對(duì)緩存功能的抽象:即允許綁定不同的緩存解決方案(如Ehcache),但本身不直接提供緩存功能的實(shí)現(xiàn)。它支持注解方式使用緩存,非常方便。
2.特點(diǎn)
- 快速
- 簡(jiǎn)單
- 多種緩存策略
- 緩存數(shù)據(jù)有兩級(jí):內(nèi)存和磁盤(pán),因此無(wú)需擔(dān)心容量問(wèn)題
- 緩存數(shù)據(jù)會(huì)在虛擬機(jī)重啟的過(guò)程中寫(xiě)入磁盤(pán)
- 可以通過(guò)RMI、可插入API等方式進(jìn)行分布式緩存
- 具有緩存和緩存管理器的偵聽(tīng)接口
- 支持多緩存管理器實(shí)例,以及一個(gè)實(shí)例的多個(gè)緩存區(qū)域
- 提供Hibernate的緩存實(shí)現(xiàn)
3.三大元素
- CacheManager : 緩存管理器,可以通過(guò)單例或者多例的方式創(chuàng)建,也是Ehcache的入口類(lèi);
- Cache : 每個(gè)CacheManager可以管理多個(gè)Cache,每個(gè)Cache可以采用hash的方式管理多個(gè)Element;
- Element : 用于存放真正緩存內(nèi)容的。
4.集成
? 可以單獨(dú)使用,ehcache在第三方用的比較多,比如mybatis、shiro中,但是對(duì)于分布式架構(gòu)中,encache顯得不是特別強(qiáng),不能多節(jié)點(diǎn)同步,通暢在這種情況下用redis。
5.示例
1.創(chuàng)建springboot項(xiàng)目,在配置文件中配置:mybatis-plus.cache-enabled = true
2.在啟動(dòng)類(lèi)上添加:@EnableCaching
3.在xml文件中添加標(biāo)簽,并添加相應(yīng)的sql執(zhí)行語(yǔ)句
mybatis-plus版本必須低于2.0.9才可以使用二級(jí)緩存,否則MP自帶的一些方法就算配置了二級(jí)緩存也不起作用。
4.在Mapper、Service層添加相應(yīng)方法之后,在Service的方法上配置緩存,key應(yīng)該是不同的,不同id的對(duì)應(yīng)不同的數(shù)據(jù)。
- ?? ①Cacheable:根據(jù)方法的請(qǐng)求參數(shù)對(duì)其結(jié)果進(jìn)行緩存,多用于查詢(xún)
- ? ②CachePut:執(zhí)行方法,并緩存結(jié)果
- ? ③CacheEvict:清空緩存
- ? ④Caching:能夠同時(shí)應(yīng)用多個(gè)緩存注解功能
- ? ⑤CacheConfig:用于抽取緩存的公共配置(類(lèi)級(jí)別)
5.我這里添加了3個(gè)接口用來(lái)做測(cè)試
?
運(yùn)行第一個(gè)接口時(shí),控制臺(tái)輸出只有一次去打開(kāi)數(shù)據(jù)庫(kù)去獲取數(shù)據(jù),其他幾次都是去緩存中獲取。
?同理第二個(gè)接口也是跟第一個(gè)接口一樣
當(dāng)我執(zhí)行更新方法之后,控制臺(tái)會(huì)打印輸出:
?此時(shí)我們?cè)偃?zhí)行第一個(gè)接口時(shí),又會(huì)去打開(kāi)數(shù)據(jù)庫(kù)取獲取數(shù)據(jù),并且數(shù)據(jù)更新了(key的關(guān)鍵作用就是指定那條數(shù)據(jù))
三、Redis
1.簡(jiǎn)介
Redis 是完全開(kāi)源免費(fèi)的,遵守BSD協(xié)議,是一個(gè)高性能的key-value數(shù)據(jù)庫(kù)。
Redis 與其他 key - value 緩存產(chǎn)品有以下三個(gè)特點(diǎn):
- Redis支持?jǐn)?shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保存在磁盤(pán)中,重啟的時(shí)候可以再次加載進(jìn)行使用。
- Redis不僅僅支持簡(jiǎn)單的key-value類(lèi)型的數(shù)據(jù),同時(shí)還提供list,set,zset,hash等數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)。
- Redis支持?jǐn)?shù)據(jù)的備份,即master-slave模式的數(shù)據(jù)備份。
2.優(yōu)勢(shì)
- 性能極高 – Redis能讀的速度是110000次/s,寫(xiě)的速度是81000次/s 。
- 豐富的數(shù)據(jù)類(lèi)型 – Redis支持二進(jìn)制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數(shù)據(jù)類(lèi)型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功執(zhí)行要么失敗完全不執(zhí)行。單個(gè)操作是原子性的。多個(gè)操作也支持事務(wù),即原子性,通過(guò)MULTI和EXEC指令包起來(lái)。
- 豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過(guò)期等等特性。
3.示例
1.引入依賴(lài)、配置
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2.在啟動(dòng)類(lèi)上添加注解:@EnableCaching
3.添加RedisConfig
package com.springboot.cache.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; 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.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.time.Duration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * @author Csea * @title * @date 2019/11/26 14:51 */ @EnableCaching @Configuration public class RedisConfig extends CachingConfigurerSupport { @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 使用Jackson2JsonRedisSerialize 替換默認(rèn)序列化 @SuppressWarnings("rawtypes") Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); // 設(shè)置value的序列化規(guī)則和 key的序列化規(guī)則 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } //緩存管理器 @Bean public CacheManager cacheManager(RedisConnectionFactory lettuceConnectionFactory) { RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig(); // 設(shè)置緩存管理器管理的緩存的默認(rèn)過(guò)期時(shí)間 defaultCacheConfig = defaultCacheConfig.entryTtl(Duration.ofMinutes(60)) // 不緩存空值 .disableCachingNullValues(); Set<String> cacheNames = new HashSet<>(); cacheNames.add("my-redis-cache1"); // 對(duì)每個(gè)緩存空間應(yīng)用不同的配置 Map<String, RedisCacheConfiguration> configMap = new HashMap<>(); configMap.put("my-redis-cache1", defaultCacheConfig.entryTtl(Duration.ofMinutes(50))); RedisCacheManager cacheManager = RedisCacheManager.builder(lettuceConnectionFactory) .cacheDefaults(defaultCacheConfig) .initialCacheNames(cacheNames) .withInitialCacheConfigurations(configMap) .build(); return cacheManager; } }
3.Mapper.xml添加執(zhí)行Sql
4.在service層配置Cache
5.controller調(diào)試
第一次請(qǐng)求時(shí)候,因?yàn)閞edis一開(kāi)始沒(méi)有數(shù)據(jù),所以會(huì)從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)并寫(xiě)入到redis中,之后就一直會(huì)從緩存中獲取數(shù)據(jù)
當(dāng)執(zhí)行了更新操作之后就會(huì)去清空redis對(duì)應(yīng)key的數(shù)據(jù)
在此執(zhí)行獲取數(shù)據(jù)時(shí),就會(huì)再去數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)并存入到redis中
4.補(bǔ)充
緩存注解:
@Cacheable、@CacheEvict、@CachePut、@Caching、@CacheConfig
- allEntries屬性:boolean類(lèi)型,表示是否需要清除緩存中的所有元素,默認(rèn)false,當(dāng)為true時(shí),Spring Cache將忽略指定的key,這樣就可以清除所有的元素緩存。
- beforeInvocation屬性:boolean類(lèi)型,默認(rèn)false,當(dāng)為true時(shí),Spring會(huì)在調(diào)用該方法之前清除緩存中的指定元素。表示的是 是否在方法執(zhí)行之前就清空緩存,在默認(rèn)情況下,如果方法執(zhí)行會(huì)拋出異常,就不會(huì)清空緩存。
- condition屬性:參數(shù)的條件,根據(jù)設(shè)置的條件返回true、false,true時(shí)才會(huì)去緩存數(shù)據(jù)。
- unless屬性:結(jié)果條件,根據(jù)結(jié)果預(yù)先設(shè)置的條件判斷true、false,true時(shí)才存入緩存。
? ①key的策略:
key屬性是用來(lái)指定Spring緩存方法的返回結(jié)果時(shí)對(duì)應(yīng)的key的。該屬性支持SpringEL表達(dá)式。當(dāng)我們沒(méi)有指定該屬性時(shí),Spring將使用默認(rèn)策略生成key。
自定義策略是指我們可以通過(guò)Spring的EL表達(dá)式來(lái)指定我們的key。
這里的EL表達(dá)式可以使用方法參數(shù)及它們對(duì)應(yīng)的屬性。
使用方法參數(shù)時(shí)我們可以直接使用“#參數(shù)名”或者“#p參數(shù)index”。
@Cacheable(value="Place",key="#placeId") PlaceInfoEntity getPlaceId(Integer placeId); @Cacheable(value="Place",key="#p0") PlaceInfoEntity getPlaceId(Integer placeId); @Cacheable(value="Place",key="#p0", condition = "#placeId >0",unless = "#result.placeName!=nullValidator") PlaceInfoEntity getPlaceId(Integer placeId); @CacheEvict(value="Place",key = "#placeInfoEntity.placeId") boolean updatePlace(PlaceInfoEntity placeInfoEntity); @CacheEvict(value="Place",key = "#p0.placeId") boolean updatePlace(PlaceInfoEntity placeInfoEntity); @CacheEvict(value="Place",key = "#p0.placeId" condition = "#placeInfoEntity.placeId > 0", unless = "#result.code != 0") boolean updatePlace(PlaceInfoEntity placeInfoEntity);
②root對(duì)象的使用:
屬性名稱(chēng) | 描述 | 示例 |
---|---|---|
methodName | 當(dāng)前方法名 | #root.methodName |
method | 當(dāng)前方法 | #root.method.name |
target | 當(dāng)前被調(diào)用的對(duì)象 | #root.target |
targetClass | 當(dāng)前被調(diào)用的對(duì)象的Class | #root.targetClass |
args | 當(dāng)前方法參數(shù)組成的數(shù)組 | #root.args[0] |
caches | 當(dāng)前被調(diào)用的方法使用的Cache | #root.caches[0].name |
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring cloud config和bus組件實(shí)現(xiàn)自動(dòng)刷新功能
今天通過(guò)本文給大家介紹spring cloud config和bus組件實(shí)現(xiàn)自動(dòng)刷新功能,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-10-10jdk17+springboot使用webservice的踩坑實(shí)戰(zhàn)記錄
這篇文章主要給大家介紹了關(guān)于jdk17+springboot使用webservice踩坑的相關(guān)資料,網(wǎng)上很多教程是基于jdk8的,所以很多在17上面跑不起來(lái),折騰兩天,直接給答案,需要的朋友可以參考下2024-01-01Java找出1000以?xún)?nèi)的所有完數(shù)
一個(gè)數(shù)如果恰好等于它的因子之和,這個(gè)數(shù)就稱(chēng)為 "完數(shù) "。例如6=1+2+3.編程找出1000以?xún)?nèi)的所有完數(shù)2017-02-02如何用idea數(shù)據(jù)庫(kù)編寫(xiě)快遞e站
這篇文章主要介紹了如何用idea數(shù)據(jù)庫(kù)編寫(xiě)快遞e站,本文通過(guò)圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01SpringBoot集成Swagger2實(shí)現(xiàn)Restful(類(lèi)型轉(zhuǎn)換錯(cuò)誤解決辦法)
這篇文章主要介紹了SpringBoot集成Swagger2實(shí)現(xiàn)Restful(類(lèi)型轉(zhuǎn)換錯(cuò)誤解決辦法),需要的朋友可以參考下2017-07-07java數(shù)據(jù)結(jié)構(gòu)基礎(chǔ):單,雙向鏈表
這篇文章主要介紹了Java的數(shù)據(jù)解構(gòu)基礎(chǔ),希望對(duì)廣大的程序愛(ài)好者有所幫助,同時(shí)祝大家有一個(gè)好成績(jī),需要的朋友可以參考下,希望能給你帶來(lái)幫助2021-07-07