框架系列——MyBatis

AbjLink發表於2024-07-31

MyBatis

MyBatis 與 Hibernate 有哪些不同?

Mybatis 相對於 Hibernate 稱為半 ORM 框架,因為 Hibernate 不需要寫 SQL,而 Mybatis 需要寫 SQL。
也因為這點 Mybatis 更加的靈活且輕量。
能針對 SQL進行最佳化,非常靈活地根據條件動態拼接 SQL等,極端情況下效能佔優。

--#{} 和 ${} 的區別

--#{} 完全相當於jdbc中的 ? 佔位符,底層在處理的時候,就是按 ?處理的 (用 PreparedStatement 的 setObject() 方法 )
如果用 #{} 這樣的方式,當引數是簡單型別的時候{} 裡的內容名稱隨意

${} 它就是當作變數值直接拼接
如果用 ${} 的方式,則{} 中間的值,通常寫成 ${value}

為什麼避免使用二級快取 ?

​ 在符合【Cache使用時的注意事項】的要求時,並沒有什麼危害。

​ 其他情況就會有很多危害了。
​ 1)針對一個表的某些操作不在他獨立的namespace下進行。
例如在UserMapper.xml中有大多數針對user表的操作。但是在一個XXXMapper.xml中,還有針對user單表的操作。
這會導致user在兩個名稱空間下的資料不一致。如果在UserMapper.xml中做了重新整理快取的操作,
在XXXMapper.xml中快取仍然有效,如果有針對user的單表查詢,使用快取的結果可能會不正確。

​ 2)更危險的情況是在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>

​ 像上面這個查詢,你會寫到那個xml中呢??

​ 不管是寫到RoleMapper.xml還是UserRoleMapper.xml,或者是一個獨立的XxxMapper.xml中。如果使用了二級快取,都會導致上面這個查詢結果可能不正確。

​ 如果你正好修改了這個使用者的角色,上面這個查詢使用快取的時候結果就是錯的。

​ 這點應該很容易理解。

​ 在我看來,就以MyBatis目前的快取方式來看是無解的。多表操作根本不能快取。

​ 如果你讓他們都使用同一個namespace(透過)來避免髒資料,那就失去了快取的意義。

Mybatis 中有兩類快取,分別是一級快取和二級快取:
級快取預設開啟,二級快取預設關閉,若開啟可在 SqlSession 之間共享快取資料。級快取預設是會話級快取。即建立一個Salsession物件就是一個會話,一次會話可能會執行多次相同的查詢,這樣快取了之後就能重複利用查詢結果,提高效能,不過 commit、rollback、update、delete 等都會清除快取。不過要注意,不同 SalSession之間的修改不會影響彼此,比如 Salsesion1 讀了資料A,SalSession2將資料改為 B,此時 SalSession1 再讀還是得到 A這就出現了髒資料的問題。
所以,如果是多 SqlSession 或者分散式環境下,就可能有髒資料的情況發生,建議將一級快取級別設定為 statement,_級快取是跨 SqlSession 級別的共享的,同一個 namespace 下的所有操作語句,都影響著同一個 Cache。

開啟二級快取之後,會先從二級快取查詢,找不到再去一級快取查詢,如果一級快取沒有再去資料庫查詢。

在分散式場景下肯定會出現髒資料建議生產上使用 redis 結合 spring cache 進行資料的快取,或者利用 guava、caffeine 進行本地快取。

相關文章