mybatis的緩存機制
在實際項目中,通常對數據庫查詢的性能要求很高,而MyBatis提供了查詢緩存來緩存數據,從而達到提高性能的要求。
MyBatis的查詢緩存分為一級緩存和二級緩存。一級緩存是sqlsession級別的緩存,二級緩存是mapper級別的緩存,二級緩存是多個sqlsession共享的。
一級緩存可用性:
一級緩存基於sqlsession,sqlsession又是單線程不共享的。所以只能在本次請求中使用,而如果本次請求有commit操作,比如update、insert、delete,那麽緩存就會被刷新。簡單來說,只有連續兩次執行相同語句,一級緩存才有效果,比如:
select * from tb_user // 執行一次SQL語句select * from tb_user // 緩存查詢
而如果有commit操作
select * from tb_user // 執行一次SQL語句 update tb_user set name = ‘lay‘ where id = 1 // commit 操作,清除了緩存 select * from tb_user // 第二次執行查詢SQL
第一種情況,個人認為基本上不太會出現。所以一級緩存在一定程度上來說,基本上沒有用。
二級緩存可用性:
二級緩存是基於mapper的,也就是說,一個mapper會有一個緩存,多個mapper會有多個緩存。並且mapper的緩存是被所有sqlsession共享的,不會因為sqlsession的關閉而清空。
select * from tb_user // 第一個sqlsession進來 select * from tb_user // 第二個sqlsession進來,查詢到的是第一個sqlsession的緩存數據
緩存清空的情況
select * from tb_user // 一個sqlsession進來 update tb_user set name = ‘lay‘ where id = 1 // 執行了commit操作,清空緩存 select * from tb_user // 第二個sqlsession進來,得重新執行sql
二級緩存屬於一個mapper,也就是當前mapper中如果執行了commit操作,當前mapper才會被清空,那麽顯而易見的問題就出現了。如果有多表關聯查詢,commit操作只清空當前的mapper,其它mapper有關聯的數據就還是舊的數據
比如:
select * from tb_user // 第一個mapper緩存了數據 select * from tb_class A left join tb_user B on A.userId = B.id // 第二個mapper緩存了數據,並關聯tb_user的數據 update tb_user set name = ‘lay‘ where id = 1 // 第一個mapper中執行了commit操作,清空了第一個mapper的緩存數據 select * from tb_class A left join tb_user B on A.userId = B.id // 第二個mapper的數據,查詢到的是緩存,而且是舊的數據
所以,由於mybatis的二級緩存的機制,多表查詢容易出現數據不一致問題,這點需要註意。當然網上也有一些解決方案,不過個人覺得那些方案會增加項目的復雜度,如果項目越來越大mapper的關聯越復雜,那些解決方案最終可能導致項目難以理解的問題。
因此,如果對數據的實時性要求不高,查詢頻率卻很高,比如某些排行榜?那麽當前mapper使用二級緩存能大大提高性能。如果對數據實時性要求很高,頻繁地執行commit操作,那麽當前mapper還是不使用二級緩存了。簡單來說,根據當前mapper的數據實時性來判斷是否使用二級緩存。
mybatis的緩存機制