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ǔ)句的效果如下:
select
?語(yǔ)句的結(jié)果將會(huì)被緩存。
insert
?、?update
?和 ?delete
?語(yǔ)句會(huì)刷新緩存。
LRU
?, ?Least Recently Used
?)算法來(lái)清除不需要的緩存。
緩存只作用于 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í)不要刷新緩存。
回想一下上一節(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"/>
更多建議: