當前位置:首頁 » 硬碟大全 » 怎麼暫時禁用mybatis緩存
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

怎麼暫時禁用mybatis緩存

發布時間: 2023-05-17 17:23:11

⑴ mybatis一級緩存內存佔用過大的問題

內存佔用過大可以通過flushCache="true"或者where <隨機數>=<隨機數>去除MyBatis的一級緩存來解決。

1、一級緩存是sqlSession級別的緩存 —— 它是各自獨立的。

在操作資料庫時需要構造sqlSession對象,在對象中有一個數據結構(HashMap)用於存儲緩存數據。

不同的sqlSession之間的緩存數據區域(HashMap)是互相不影響的。

2、二級緩存是mapper級別的緩存 —— 它是多個 SqlSession 共享的。

多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的。

⑵ mybatis的cache-ref怎麼使用

首先明確一點 cache-ref 只對二級緩存有效,沒有使用二級緩存時,這東西沒有意義。
以下說明只針對二級緩存。
當mybatis的當前命名空間存在DML的事務提交時,會使當前命名空間里的緩存失效,這樣在查詢時,會直接從資料庫拿到數據,並再次緩存。但是如果是多表連接查詢,如tableA join tableB,A表的DML操作在A的nameSpace,B表的DML操作在B的nameSpace,當B表在進行了數據修改時,不會使A表緩存失效,再使用tableA join tableB會直接從緩存中獲取數據,因為此時緩存沒有刷新,而且B表的數據也有變化,那麼此時讀取的就是臟數據。
此時就需要在B的nameSpace里使用<cache-ref namespace="A"/>,保證跟新B時,A的緩存也失效。再在A裡面執行 tableA join tableB時,會重新從資料庫里查詢最新數據。

⑶ MyBatis二級緩存帶來的問題

MyBatis二級緩存使用的在某些場景下會出問題,來看一下為什麼這么說。

假設我有一條select語句(開啟了二級緩存):

selecta.col1, a.col2, a.col3, b.col1, b.col2, b.col3fromtableA a, tableB bwherea.id= b.id;

對於tableA與tableB的操作定義在兩個Mapper中,分別叫做MapperA與MapperB,即它們屬於兩個命名空間,如果此時啟用緩存:

MapperA中執行上述sql語句查詢這6個欄位

tableB更新了col1與col2兩個欄位

MapperA再次執行上述sql語句查詢這6個欄位(前提是沒有執行過任何insert、delete、update操作)

此時問題就來了,即使第(2)步tableB更新了col1與col2兩個欄位,第(3)步MapperA走二級緩存查詢到的這6個欄位依然是原來的這6個欄位的值,因為我們從CacheKey的3組條件來看:

<select>標簽所在的Mapper的Namespace+<select>標簽的id屬性

RowBounds的offset和limit屬性,RowBounds是MyBatis用於處理分頁的一個類,offset默認為0,limit默認為Integer.MAX_VALUE

<select>標簽中定義的sql語句

對於MapperA來說,其中的任何一個條件都沒有變化,自然會將原結果返回。

這個問題對於MyBatis的二級緩存來說是一個無解的問題,因此使用MyBatis二級緩存有一個前提: 必須保證所有的增刪改查都在同一個命名空間下才行 。

⑷ Mybatis的緩存講解

前段時間阿粉的一個朋友和阿粉吃飯,在吃飯的時候和阿粉瘋狂的吐槽面試官,說面試官問的問題都是些什麼問題呀,我一個幹了三四年的開發,也不說問點靠譜的,阿粉很好奇,問題問完基礎的,一般不都是根據你自己的簡歷進行提問么?而接下來他說的出來的問題,阿粉表示,阿粉需要繼續學習了。

說到這個,讀者大人們肯定心想,阿粉是在開玩笑么?你一個 Java 程序員,你不知道Mybatis是啥么?不就是個持久層的框架么,這東西有啥好說的呢?但是阿粉還是要給大家說。

為什麼說 Mybatis 是一個半自動 ORM 的框架呢?

ORM,是Object和Relation之間的映射,而Mybatis 在查詢關聯對象或關聯集合對象時,需要手動編寫 sql 來完成,所以,稱之為半自動 ORM 框架,而Hibernate 屬於全自動 ORM 映射工具,使用 Hibernate 查詢關聯對象或者關聯集合對象時,可以根據對象關系模型直接獲取,所以它是全自動的。

這也是為什麼有些面試官在面試初級程序員的時候,很喜歡說,你覺得 Mybatis , 和 Hibernate 都有什麼優缺點,為啥你們選擇使用的 Mybatis 而不選擇使用 Hibernate 呢?

我們都說了 Mybatis是什麼了,接下來肯定需要說說面試官都問了什麼問題,能讓阿粉的朋友變得非常猶豫。

當我們面試的時候,說完這個,一般情況下,面試官一定會追問下去,畢竟技術就是要問到你的知識盲區才會停止。

那我們就來畫個圖表示一下一級緩存

那面試官肯定會說,直接從資料庫查不就行了,為啥要一級緩存呢?

當我們使用MyBatis開啟一次和資料庫的會話時, MyBatis 會創建出一個 SqlSession 對象表示一次與資料庫之間的信息傳遞,在我們執行 SQL 語句的過程中,們可能會反復執行完全相同的查詢語句,如果不採取一些措施,我們每一次查詢都會查詢一次資料庫,而如果在極短的時間內做了很多次相同的查詢操作,那麼這些查詢返回的結果很可能相同。

也就是說,如果我們在短時間內,頻繁的去執行一條 SQL ,查詢返回的結果本來應該是改變了,但是我們查詢出來的時候,會出現結果一致的情況,正是為了解決這種問題,也為了減輕資料庫的開銷,所以 Mybatis 默認開啟了一級緩存。

Mybatis 的二級緩存一般如果你不對他進行設置,他是不會開啟的,而二級緩存是什麼呢?Mybatis 中的二級緩存實際上就是 mapper 級別的緩存,而這時候肯定會有人說,那麼不同之間的 Mapper 是同一個緩存么?

答案是否定的,他不是一個,Mapper 級別的緩存實際上就是相同的 Mapper 使用的是一個二級緩存,但是在二級緩存中,又有多個不同的 SqlSession ,而不同的 Mapper 之間的二級緩存也就是互相不會影響的。

就類似下面的圖

這二級緩存是不是就看起來有點意思了?

那怎麼能夠開啟二級緩存呢?

1.MyBatis 配置文件

2.MyBatis 要求返回的 POJO 必須是可序列化的

3.Mapper 的 xml 配置文件中加入 標簽

既然我們想要了解這個二級緩存,那麼必然,我們還得知道它裡面的配置都有哪些含義。

我們先從標簽看起,然後從源碼裡面看都有哪些配置信息提供給我們使用:

blocking : 直譯就是調度,而在 Mybatis 中,如果緩存中找不到對應的 key ,是否會一直 blocking ,直到有對應的數據進入緩存。

eviction : 緩存回收策略

而緩存回收策略,在源碼中是有直接體現的,那麼他們分別都對應了什麼形式呢?

大家雖然看著 PERPETUAL 排在了第一位,但是它可不是默認的,在 Mybatis 的緩存策略裡面,默認的是 LRU 。

PERPETUAL :

源代碼如下:

恩?看著是不是有點眼熟,它怎麼就只是包裝了 HashMap ? 你還別奇怪,他還真的就是使用的 HashMap ,不得不說,雖然人家是使用的 HashMap ,但是那可是比咱們寫的高端多了。

既然使用 HashMap ,那麼必然就會有Key,那麼他們的Key是怎麼設計的?

CacheKey:

確實牛逼,至於內部如何初始化,如何進行操作,大家有興趣的可以去閱讀一下源碼,導入個源碼包,打開自己看一下。

FIFO : 先進先出緩沖淘汰策略

在 FIFO 淘汰策略中使用了 Java 中的 Deque,而 Deque 一種常用的數據結構,可以將隊列看做是一種特殊的線性表,該結構遵循的先進先出原則。Java中,LinkedList實現了Queue介面,因為LinkedList進行插入、刪除操作效率較高。

當你看完這個源碼的時候,是不是就感覺源碼其實也沒有那麼難看懂,裡面都是我們已經掌握好的知識,只不過中間做了一些操作,進行了一些封裝。

LRU : 最近最少使用的緩存策略

而 LUR 演算法,阿粉之前都說過,如果對這個演算法感興趣的話,文章地址給大家送上,經典的 LRU 演算法,你真的了解嗎?

而我們需要看的源碼則是在 Mybatis 中的源碼,

SOFT : 基於垃圾回收器狀態和軟引用規則的對象

在看到基於垃圾回收器的時候,阿粉就已經開始興奮了,竟然有GC的事情,那還不趕緊看看,這如此高大上(裝杯)的事情,來瞅瞅吧!

WEAK : 基於垃圾收集器狀態和弱引用規則的對象

WeakCache在實現上與SoftCache幾乎相同,只是把引用對象由SoftReference軟引用換成了WeakReference弱引用。

在這里阿粉也就不再多說了,關於 Mybatis 的二級緩存,你了解了么?下次遇到面試官問這個的時候,你應該知道怎麼成功(裝杯)不被打了吧。

⑸ mybatis 二級緩存怎麼使用

深入了解MyBatis二級緩存
一、創建Cache的完整過程
我們從SqlSessionFactoryBuilder解析mybatis-config.xml配置文件開始:
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

然後是:
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());

看parser.parse()方法:
parseConfiguration(parser.evalNode("/configuration"));

看處理Mapper.xml文件的位置:
mapperElement(root.evalNode("mappers"));

看處理Mapper.xml的XMLMapperBuilder:
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration,
resource, configuration.getSqlFragments());
mapperParser.parse();

繼續看parse方法:
configurationElement(parser.evalNode("/mapper"));

到這里:
String namespace = context.getStringAttribute("namespace");
if (namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
cacheRefElement(context.evalNode("cache-ref"));
cacheElement(context.evalNode("cache"));

從這里看到namespace就是xml中<mapper>元素的屬性。然後下面是先後處理的cache-ref和cache,後面的cache會覆蓋前面的cache-ref,但是如果一開始cache-ref沒有找到引用的cache,他就不會被覆蓋,會一直到最後處理完成為止,最後如果存在cache,反而會被cache-ref覆蓋。這里是不是看著有點暈、有點亂?所以千萬別同時配置這兩個,實際上也很少有人會這么做。
看看MyBatis如何處理<cache/>:
private void cacheElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type", "PERPETUAL");
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
String eviction = context.getStringAttribute("eviction", "LRU");
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
Long flushInterval = context.getLongAttribute("flushInterval");
Integer size = context.getIntAttribute("size");
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
boolean blocking = context.getBooleanAttribute("blocking", false);
Properties props = context.getChildrenAsProperties();
builderAssistant.useNewCache(typeClass, evictionClass,
flushInterval, size, readWrite, blocking, props);
}
}

從源碼可以看到MyBatis讀取了那些屬性,而且很容易可以到這些屬性的默認值。
創建Java的cache對象方法為builderAssistant.useNewCache,我們看看這段代碼:
public Cache useNewCache(Class<? extends Cache> typeClass,
Class<? extends Cache> evictionClass,
Long flushInterval,
Integer size,
boolean readWrite,
boolean blocking,
Properties props) {
typeClass = valueOrDefault(typeClass, PerpetualCache.class);
evictionClass = valueOrDefault(evictionClass, LruCache.class);
Cache cache = new CacheBuilder(currentNamespace)
.implementation(typeClass)
.addDecorator(evictionClass)
.clearInterval(flushInterval)
.size(size)
.readWrite(readWrite)
.blocking(blocking)
.properties(props)
.build();
configuration.addCache(cache);
currentCache = cache;
return cache;
}

從調用該方法的地方,我們可以看到並沒有使用返回值cache,在後面的過程中創建MappedStatement的時候使用了currentCache。
二、使用Cache過程
在系統中,使用Cache的地方在CachingExecutor中:
@Override
public <E> List<E> query(
MappedStatement ms, Object parameterObject,
RowBounds rowBounds, ResultHandler resultHandler,
CacheKey key, BoundSql boundSql) throws SQLException {
Cache cache = ms.getCache();

獲取cache後,先判斷是否有二級緩存。
只有通過<cache/>,<cache-ref/>或@CacheNamespace,@CacheNamespaceRef標記使用緩存的Mapper.xml或Mapper介面(同一個namespace,不能同時使用)才會有二級緩存。
if (cache != null) {

如果cache存在,那麼會根據sql配置(<insert>,<select>,<update>,<delete>的flushCache屬性來確定是否清空緩存。
flushCacheIfRequired(ms);

然後根據xml配置的屬性useCache來判斷是否使用緩存(resultHandler一般使用的默認值,很少會null)。
if (ms.isUseCache() && resultHandler == null) {

確保方法沒有Out類型的參數,mybatis不支持存儲過程的緩存,所以如果是存儲過程,這里就會報錯。
ensureNoOutParams(ms, parameterObject, boundSql);

沒有問題後,就會從cache中根據key來取值:
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);

如果沒有緩存,就會執行查詢,並且將查詢結果放到緩存中。
if (list == null) {
list = delegate.<E>query(ms, parameterObject,
rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}

返回結果
return list;
}
}

沒有緩存時,直接執行查詢
return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

在上面的代碼中tcm.putObject(cache, key, list);這句代碼是緩存了結果。但是實際上直到sqlsession關閉,MyBatis才以序列化的形式保存到了一個Map(默認的緩存配置)中。

三、Cache使用時的注意事項
1. 只能在【只有單表操作】的表上使用緩存
不只是要保證這個表在整個系統中只有單表操作,而且和該表有關的全部操作必須全部在一個namespace下。
2. 在可以保證查詢遠遠大於insert,update,delete操作的情況下使用緩存
這一點不需要多說,所有人都應該清楚。記住,這一點需要保證在1的前提下才可以!

四、避免使用二級緩存
可能會有很多人不理解這里,二級緩存帶來的好處遠遠比不上他所隱藏的危害。
緩存是以namespace為單位的,不同namespace下的操作互不影響。
insert,update,delete操作會清空所在namespace下的全部緩存。
通常使用MyBatis Generator生成的代碼中,都是各個表獨立的,每個表都有自己的namespace。
為什麼避免使用二級緩存
在符合【Cache使用時的注意事項】的要求時,並沒有什麼危害。
其他情況就會有很多危害了。
針對一個表的某些操作不在他獨立的namespace下進行。
例如在UserMapper.xml中有大多數針對user表的操作。但是在一個XXXMapper.xml中,還有針對user單表的操作。
這會導致user在兩個命名空間下的數據不一致。如果在UserMapper.xml中做了刷新緩存的操作,在XXXMapper.xml中緩存仍然有效,如果有針對user的單表查詢,使用緩存的結果可能會不正確。
更危險的情況是在XXXMapper.xml做了insert,update,delete操作時,會導致UserMapper.xml中的各種操作充滿未知和風險。
有關這樣單表的操作可能不常見。但是你也許想到了一種常見的情況。
多表操作一定不能使用緩存
為什麼不能?
首先不管多表操作寫到那個namespace下,都會存在某個表不在這個namespace下的情況。
例如兩個表:role和user_role,如果我想查詢出某個用戶的全部角色role,就一定會涉及到多表的操作。
<select id="selectUserRoles" resultType="UserRoleVO">
select * from user_role a,role b where a.roleid = b.roleid and a.userid = #{userid}
</select>123123

像上面這個查詢,你會寫到那個xml中呢??
不管是寫到RoleMapper.xml還是UserRoleMapper.xml,或者是一個獨立的XxxMapper.xml中。如果使用了二級緩存,都會導致上面這個查詢結果可能不正確。
如果你正好修改了這個用戶的角色,上面這個查詢使用緩存的時候結果就是錯的。
這點應該很容易理解。
在我看來,就以MyBatis目前的緩存方式來看是無解的。多表操作根本不能緩存。
如果你讓他們都使用同一個namespace(通過<cache-ref>)來避免臟數據,那就失去了緩存的意義。
看到這里,實際上就是說,二級緩存不能用。整篇文章介紹這么多也沒什麼用了。

五、挽救二級緩存?
想更高效率的使用二級緩存是解決不了了。
但是解決多表操作避免臟數據還是有法解決的。解決思路就是通過攔截器判斷執行的sql涉及到那些表(可以用jsqlparser解析),然後把相關表的緩存自動清空。但是這種方式對緩存的使用效率是很低的。
設計這樣一個插件是相當復雜的,既然我沒想著去實現,就不廢話了。
最後還是建議,放棄二級緩存,在業務層使用可控制的緩存代替更好。

⑹ 如何讓sqlmapsession不緩存記錄

每次用完都重定向一下引用地址NULL

⑺ mybatis的緩存機制是怎麼樣的

你好,正如大多數持久層框架一樣,MyBatis 同樣提供了一級緩存和二級緩存的支持。
1.緩存,其存儲作用域為 Session,當 Session flush 或 close 之後,該Session中的所有 Cache 就將清空。
2. 二級緩存與一級緩存其機制相同,默認也是採用 PerpetualCache,HashMap存儲,不同在於其存儲作用域為 Mapper(Namespace),並且可自定義存儲源,如 Ehcache。
3. 對於緩存數據更新機制,當某一個作用域(一級緩存Session/二級緩存Namespaces)的進行了 C/U/D 操作後,默認該作用域下所有 select 中的緩存將被clear。

mybatis的一級緩存作用就是在同一個session過程中,將會對相同數據的存取不通過資料庫,而是通過緩存機制提高效率。
希望對你有幫助~

⑻ mybatis的緩存機制是怎麼樣的

你好
關於mybatis的緩存機制:
和其他持久層框架一樣,mybatis也提供了對緩存的支持--一級緩存和二級緩存;
一、緩存介紹
一級緩存:基於PerpetualCache的HashMap的本地緩存,一級緩存的作用域為sqlSession,當sqlSession被flush或close之後,當前sqlSession中的所有緩存都將被清空;
二級緩存:和一級緩存的機制相同,默認也是採用PerpetualCache的HashMap存儲,但二級緩存的作用域是mapper(namespace);
在mybatis的緩存機制中,當緩存(一級緩存的sqlSession/二級緩存的namespace)進行了增刪改的操作之後,當前select的所有數據緩存都將被清除;
總結
二級緩存與一級緩存區別,二級緩存的范圍更大,多個sqlSession可以共享一個UserMapper的二級緩存區域。UserMapper有一個二級緩存區域(按namespace分) ,其它mapper也有自己的二級緩存區域(按namespace分)。每一個namespace的mapper都有一個二緩存區域,兩個mapper的namespace如果相同,這兩個mapper執行sql查詢到數據將存在相同 的二級緩存區域中。
希望對你有幫助

⑼ MyBatis中如何禁用緩存

默認情況下,select語句總是使用緩存,但有些情況下,我們希望它總是刷新從而得到最新數據,看了下它的文檔,配置不起作用,對配置文件的

<settings>
<setting name="cacheEnabled" value="false"/>
</settings>

不起作用,對sql映射文件的
flushCache="true" useCache="false"
仍然不起作用,最後找到了徹底的辦法,調用SqlSession.clearCache(),問題解決。