MyBatis 3 XML映射文件-緩存

2022-04-11 10:11 更新

MyBatis 內(nèi)置了一個(gè)強(qiáng)大的事務(wù)性查詢緩存機(jī)制,它可以非常方便地配置和定制。 為了使它更加強(qiáng)大而且易于配置,我們對(duì) MyBatis 3 中的緩存實(shí)現(xiàn)進(jìn)行了許多改進(jìn)。

默認(rèn)情況下,只啟用了本地的會(huì)話緩存,它僅僅對(duì)一個(gè)會(huì)話中的數(shù)據(jù)進(jìn)行緩存。 要啟用全局的二級(jí)緩存,只需要在你的 SQL 映射文件中添加一行:

<cache/>

基本上就是這樣。這個(gè)簡(jiǎn)單語(yǔ)句的效果如下:

  • 映射語(yǔ)句文件中的所有 ?select ?語(yǔ)句的結(jié)果將會(huì)被緩存。
  • 映射語(yǔ)句文件中的所有 ?insert?、?update ?和 ?delete ?語(yǔ)句會(huì)刷新緩存。
  • 緩存會(huì)使用最近最少使用算法(?LRU?, ?Least Recently Used?)算法來(lái)清除不需要的緩存。
  • 緩存不會(huì)定時(shí)進(jìn)行刷新(也就是說(shuō),沒(méi)有刷新間隔)。
  • 緩存會(huì)保存列表或?qū)ο螅o(wú)論查詢方法返回哪種)的 1024 個(gè)引用。
  • 緩存會(huì)被視為讀/寫(xiě)緩存,這意味著獲取到的對(duì)象并不是共享的,可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改。

緩存只作用于 cache 標(biāo)簽所在的映射文件中的語(yǔ)句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的語(yǔ)句將不會(huì)被默認(rèn)緩存。你需要使用 ?@CacheNamespaceRef? 注解指定緩存作用域。

這些屬性可以通過(guò) cache 元素的屬性來(lái)修改。比如:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

這個(gè)更高級(jí)的配置創(chuàng)建了一個(gè) ?FIFO ?緩存,每隔 60 秒刷新,最多可以存儲(chǔ)結(jié)果對(duì)象或列表的 512 個(gè)引用,而且返回的對(duì)象被認(rèn)為是只讀的,因此對(duì)它們進(jìn)行修改可能會(huì)在不同線程中的調(diào)用者產(chǎn)生沖突。

可用的清除策略有:

  • ?LRU ?– 最近最少使用:移除最長(zhǎng)時(shí)間不被使用的對(duì)象。
  • ?FIFO ?– 先進(jìn)先出:按對(duì)象進(jìn)入緩存的順序來(lái)移除它們。
  • ?SOFT ?– 軟引用:基于垃圾回收器狀態(tài)和軟引用規(guī)則移除對(duì)象。
  • ?WEAK ?– 弱引用:更積極地基于垃圾收集器狀態(tài)和弱引用規(guī)則移除對(duì)象。

默認(rèn)的清除策略是 ?LRU?。

?flushInterval?(刷新間隔)屬性可以被設(shè)置為任意的正整數(shù),設(shè)置的值應(yīng)該是一個(gè)以毫秒為單位的合理時(shí)間量。 默認(rèn)情況是不設(shè)置,也就是沒(méi)有刷新間隔,緩存僅僅會(huì)在調(diào)用語(yǔ)句時(shí)刷新。

?size?(引用數(shù)目)屬性可以被設(shè)置為任意正整數(shù),要注意欲緩存對(duì)象的大小和運(yùn)行環(huán)境中可用的內(nèi)存資源。默認(rèn)值是 1024。

?readOnly?(只讀)屬性可以被設(shè)置為 ?true ?或 ?false?。只讀的緩存會(huì)給所有調(diào)用者返回緩存對(duì)象的相同實(shí)例。 因此這些對(duì)象不能被修改。這就提供了可觀的性能提升。而可讀寫(xiě)的緩存會(huì)(通過(guò)序列化)返回緩存對(duì)象的拷貝。 速度上會(huì)慢一些,但是更安全,因此默認(rèn)值是 ?false?。

二級(jí)緩存是事務(wù)性的。這意味著,當(dāng) ?SqlSession ?完成并提交時(shí),或是完成并回滾,但沒(méi)有執(zhí)行 ?flushCache=true? 的 ?insert?/?delete?/?update ?語(yǔ)句時(shí),緩存會(huì)獲得更新。

使用自定義緩存

除了上述自定義緩存的方式,你也可以通過(guò)實(shí)現(xiàn)你自己的緩存,或?yàn)槠渌谌骄彺娣桨竸?chuàng)建適配器,來(lái)完全覆蓋緩存行為。

<cache type="com.domain.something.MyCustomCache"/>

這個(gè)示例展示了如何使用一個(gè)自定義的緩存實(shí)現(xiàn)。?type ?屬性指定的類必須實(shí)現(xiàn) ?org.apache.ibatis.cache.Cache? 接口,且提供一個(gè)接受 ?String ?參數(shù)作為 id 的構(gòu)造器。 這個(gè)接口是 MyBatis 框架中許多復(fù)雜的接口之一,但是行為卻非常簡(jiǎn)單。

public interface Cache {
  String getId();
  int getSize();
  void putObject(Object key, Object value);
  Object getObject(Object key);
  boolean hasKey(Object key);
  Object removeObject(Object key);
  void clear();
}

為了對(duì)你的緩存進(jìn)行配置,只需要簡(jiǎn)單地在你的緩存實(shí)現(xiàn)中添加公有的 ?JavaBean ?屬性,然后通過(guò) ?cache ?元素傳遞屬性值,例如,下面的例子將在你的緩存實(shí)現(xiàn)上調(diào)用一個(gè)名為 ?setCacheFile(String file)? 的方法:

<cache type="com.domain.something.MyCustomCache">
  <property name="cacheFile" value="/tmp/my-custom-cache.tmp"/>
</cache>

你可以使用所有簡(jiǎn)單類型作為 ?JavaBean ?屬性的類型,MyBatis 會(huì)進(jìn)行轉(zhuǎn)換。 你也可以使用占位符(如 ?${cache.file}?),以便替換成在配置文件屬性中定義的值。

從版本 3.4.2 開(kāi)始,MyBatis 已經(jīng)支持在所有屬性設(shè)置完畢之后,調(diào)用一個(gè)初始化方法。 如果想要使用這個(gè)特性,請(qǐng)?jiān)谀愕淖远x緩存類里實(shí)現(xiàn) ?org.apache.ibatis.builder.InitializingObject? 接口。

public interface InitializingObject {
  void initialize() throws Exception;
}

上一節(jié)中對(duì)緩存的配置(如清除策略、可讀或可讀寫(xiě)等),不能應(yīng)用于自定義緩存。

請(qǐng)注意,緩存的配置和緩存實(shí)例會(huì)被綁定到 SQL 映射文件的命名空間中。 因此,同一命名空間中的所有語(yǔ)句和緩存將通過(guò)命名空間綁定在一起。 每條語(yǔ)句可以自定義與緩存交互的方式,或?qū)⑺鼈兺耆懦诰彺嬷?,這可以通過(guò)在每條語(yǔ)句上使用兩個(gè)簡(jiǎn)單屬性來(lái)達(dá)成。 默認(rèn)情況下,語(yǔ)句會(huì)這樣來(lái)配置:

<select ... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>

鑒于這是默認(rèn)行為,顯然你永遠(yuǎn)不應(yīng)該以這樣的方式顯式配置一條語(yǔ)句。但如果你想改變默認(rèn)的行為,只需要設(shè)置 ?flushCache ?和 ?useCache ?屬性。比如,某些情況下你可能希望特定 ?select ?語(yǔ)句的結(jié)果排除于緩存之外,或希望一條 ?select ?語(yǔ)句清空緩存。類似地,你可能希望某些 ?update ?語(yǔ)句執(zhí)行時(shí)不要刷新緩存。

cache-ref

回想一下上一節(jié)的內(nèi)容,對(duì)某一命名空間的語(yǔ)句,只會(huì)使用該命名空間的緩存進(jìn)行緩存或刷新。 但你可能會(huì)想要在多個(gè)命名空間中共享相同的緩存配置和實(shí)例。要實(shí)現(xiàn)這種需求,你可以使用 cache-ref 元素來(lái)引用另一個(gè)緩存。

<cache-ref namespace="com.someone.application.data.SomeMapper"/>


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)