MyBatis 3 XML映射文件-緩存

2022-04-11 10:11 更新

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

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

<cache/>

基本上就是這樣。這個簡單語句的效果如下:

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

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

這些屬性可以通過 cache 元素的屬性來修改。比如:

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

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

可用的清除策略有:

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

默認的清除策略是 ?LRU?。

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

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

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

二級緩存是事務性的。這意味著,當 ?SqlSession ?完成并提交時,或是完成并回滾,但沒有執(zhí)行 ?flushCache=true? 的 ?insert?/?delete?/?update ?語句時,緩存會獲得更新。

使用自定義緩存

除了上述自定義緩存的方式,你也可以通過實現(xiàn)你自己的緩存,或為其他第三方緩存方案創(chuàng)建適配器,來完全覆蓋緩存行為。

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

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

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();
}

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

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

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

從版本 3.4.2 開始,MyBatis 已經(jīng)支持在所有屬性設置完畢之后,調(diào)用一個初始化方法。 如果想要使用這個特性,請在你的自定義緩存類里實現(xiàn) ?org.apache.ibatis.builder.InitializingObject? 接口。

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

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

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

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

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

cache-ref

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

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


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號