Mybatis——一級快取與二級快取
關於Mybatis的學習主要參考了狂神的視訊
-
一級快取
(1).使用範圍:從sqlSession會話開始到結束
(2).使用:預設開啟,無法關閉
(3).測試使用(需要開啟日誌觀察資料庫的連線情況):
public static void Maintest(){ SqlSession sqlSession = Connection.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); HashMap map = new HashMap(); map.put("UId","3180421016"); List<UserBean> userBeans = userMapper.queryByIf(map); map.put("UName","關晨亮"); //userMapper.updateById(map); System.out.println(userMapper.queryByIf(map).get(0).equals(userBeans.get(0))); sqlSession.close(); } //result:true,將結果集列印,可以看出兩次結果集列印之間是沒有再做資料庫連線的
(4).快取失效的4種情況:
-
sqlSession不同
public static void Maintest(){ SqlSession sqlSession1 = Connection.getSqlSession(); SqlSession sqlSession2 = Connection.getSqlSession(); UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); HashMap map = new HashMap(); map.put("UId","3180421016"); List<UserBean> userBeans = userMapper1.queryByIf(map); System.out.println(userBeans); sqlSession1.close(); System.out.println(userBeans.get(0).equals(userMapper2.queryByIf(map).get(0))); sqlSession2.close(); }
-
sqlSession相同,兩次查詢操作之間存在增刪改操作
public static void Maintest(){ SqlSession sqlSession = Connection.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); HashMap map = new HashMap(); map.put("UId","3180421016"); List<UserBean> userBeans = userMapper.queryByIf(map); map.put("UName","關晨亮"); userMapper.updateById(map); System.out.println(userMapper.queryByIf(map).get(0).equals(userBeans.get(0))); sqlSession.close(); } //result:false,將結果集列印,可以看出兩次結果集列印之間是有再次做過資料庫連線的
-
sqlSession相同,查詢條件不同(此時快取中沒有相關資料)
public static void Maintest(){ SqlSession sqlSession1 = Connection.getSqlSession(); UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); HashMap map = new HashMap(); map.put("UId","3180421016"); List<UserBean> userBeans = userMapper1.queryByIf(map); System.out.println(userBeans); map.put("UId","2"); userBeans = userMapper1.queryByIf(map); System.out.println(userBeans); sqlSession1.close(); } //開啟日誌可以看到,發生了兩次對於資料庫的連線請求
-
通過session.clearCache()主動重新整理快取
public static void Maintest(){ SqlSession sqlSession1 = Connection.getSqlSession(); UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); HashMap map = new HashMap(); map.put("UId","3180421016"); List<UserBean> userBeans = userMapper1.queryByIf(map); System.out.println(userBeans); sqlSession1.clearCache(); userBeans = userMapper1.queryByIf(map); System.out.println(userBeans); sqlSession1.close(); }
-
-
二級快取
(1).簡介
- 作用範圍:整個namespace,也就是一個mapper
- 實現:不同的mapper查出的資料會放在對應的快取(map)中
(2).使用:
- 在主配置檔案中顯式地開啟二級快取
<settings> <!-- <setting name="logImpl" value="LOG4J"/>--> <setting name="logImpl" value="STDOUT_LOGGING"/> <setting name="cacheEnabled" value="true"/> </settings>
- 在Mapper.xml中配置(為什麼要開啟readOnly會在後面解釋)
<cache readOnly="true"/>
或
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
- 測試
public static void Maintest(){ SqlSession sqlSession1 = Connection.getSqlSession(); SqlSession sqlSession2 = Connection.getSqlSession(); UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); HashMap map = new HashMap(); map.put("UId","3180421016"); List<UserBean> userBeans = userMapper1.queryByIf(map); sqlSession1.close(); System.out.println(userBeans.get(0).equals(userMapper2.queryByIf(map).get(0))); sqlSession2.close(); } /result:true
(3).注意
- 需要實體序列化
客戶端訪問了某個能開啟會話功能的資源, web伺服器就會建立一個與該客戶端對應的HttpSession物件,每個HttpSession物件都要站用一定的記憶體空間。如果在某一時間段內訪問站點的使用者很多,web伺服器記憶體中就會積累大量的HttpSession物件,消耗大量的伺服器記憶體,即使使用者已經離開或者關閉了瀏覽器,web伺服器仍要保留與之對應的HttpSession物件,在他們超時之前,一直佔用web伺服器記憶體資源。
web伺服器通常將那些暫時不活動但未超時的HttpSession物件轉移到檔案系統或資料庫中儲存,伺服器要使用他們時再將他們從檔案系統或資料庫中裝載入記憶體,這種技術稱為Session的持久化。
將HttpSession物件儲存到檔案系統或資料庫中,需要採用序列化的方式將HttpSession物件中的每個屬性物件儲存到檔案系統或資料庫中;將HttpSession物件從檔案系統或資料庫中裝載如記憶體時,需要採用反序列化的方式,恢復HttpSession物件中的每個屬性物件。所以儲存在HttpSession物件中的每個屬性物件必須實現Serializable介面
public class UserBean implements Serializable { private String UId; private String UName; private int USet; private int UAuth; private String UPassword; private int UState; }
- 必須開啟只讀,否則兩次比較的結果不同
只讀的快取會給所有呼叫者返回快取物件的相同例項。 因此這些物件不能被修改。這就提供了可觀的效能提升。而可讀寫的快取會(通過序列化)返回快取物件的拷貝。 速度上會慢一些,但是更安全,因此預設值是 false。
<cache readOnly="true"/>
-
快取優先放在以及會話中,當會話關閉後,快取才會被轉移到二級會話
public static void Maintest(){ SqlSession sqlSession1 = Connection.getSqlSession(); SqlSession sqlSession2 = Connection.getSqlSession(); UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); HashMap map = new HashMap(); map.put("UId","3180421016"); List<UserBean> userBeans = userMapper1.queryByIf(map); System.out.println(userBeans); System.out.println(userBeans.get(0).equals(userMapper2.queryByIf(map).get(0))); sqlSession1.close(); sqlSession2.close(); } //false,因為還沒有關閉就開始比較了
public static void Maintest(){ SqlSession sqlSession1 = Connection.getSqlSession(); SqlSession sqlSession2 = Connection.getSqlSession(); UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); HashMap map = new HashMap(); map.put("UId","3180421016"); List<UserBean> userBeans = userMapper1.queryByIf(map); System.out.println(userBeans); sqlSession1.close(); System.out.println(userBeans.get(0).equals(userMapper2.queryByIf(map).get(0))); sqlSession2.close(); } //true,因為是會話關閉之後再比較的
-
對於查詢(select),我們可以使用useCache來選擇是否取消快取;對於增刪改,可以使用flushCache來選擇是否取消更新快取
-
快取原理,這邊用狂神的圖來加深理解
-
使用ehcache外部快取
(1).導包
(2).寫配置檔案.xml
(3).在主配置檔案中使用:設定cache標籤的type屬性
注:現在多用redis資料庫