MyBatis 內(nèi)置了一個強大的事務性查詢緩存機制,它可以非常方便地配置和定制。 為了使它更加強大而且易于配置,我們對 MyBatis 3 中的緩存實現(xiàn)進行了許多改進。
默認情況下,只啟用了本地的會話緩存,它僅僅對一個會話中的數(shù)據(jù)進行緩存。 要啟用全局的二級緩存,只需要在你的 SQL 映射文件中添加一行:
<cache/>
基本上就是這樣。這個簡單語句的效果如下:
select
?語句的結(jié)果將會被緩存。
insert
?、?update
?和 ?delete
?語句會刷新緩存。
LRU
?, ?Least Recently Used
?)算法來清除不需要的緩存。
緩存只作用于 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í)行時不要刷新緩存。
回想一下上一節(jié)的內(nèi)容,對某一命名空間的語句,只會使用該命名空間的緩存進行緩存或刷新。 但你可能會想要在多個命名空間中共享相同的緩存配置和實例。要實現(xiàn)這種需求,你可以使用 cache-ref 元素來引用另一個緩存。
<cache-ref namespace="com.someone.application.data.SomeMapper"/>
更多建議: