咱們能夠將一些變更不大且訪問頻率高的數據,放置在一個緩存容器中,用戶下一次查詢時就從緩存容器中獲取結果。java
一級緩存是基於同一個SqlSession類的實例對象的。不一樣的SqlSession類的實例對象緩存的數據區域是互不影響的。MyBatis默認支持一級緩存。sql
例如,使用同一個sqlSession對象,對id爲1的用戶查詢兩次:數據庫
@Test public void testFindCustomerCache1() throws Exception{ SqlSession sqlSession=dataConnection.getSqlSession(); //調用userMapper的方法 User user1= sqlSession.selectOne("test.findUserById",1); System.out.println("用戶姓名:"+user1.getUsername()); User user2= sqlSession.selectOne("test.findUserById",1); System.out.println("用戶姓名:"+user2.getUsername()); sqlSession.close(); }
查看運行結果:
從圖中能夠看出第一次查詢id爲1的用戶信息時,首先打開數據庫鏈接,創建數據庫鏈接,而後預編譯SQL語句,設置輸入參數,最後從數據庫中查詢了id爲1的用戶的信息。而第二次查詢id爲1的用戶時,發現沒有任何日誌輸出,僅僅打印了取出數據時的信息,這說明第二次數據不是從數據庫查詢出來的,是從一級緩存中獲取的。緩存
在第二次查詢id爲1的用戶的信息以前,修改用戶的一個屬性:服務器
@Test public void testFindCustomerCache2() throws Exception{ SqlSession sqlSession=dataConnection.getSqlSession(); //調用userMapper的方法 User user1= sqlSession.selectOne("test.findUserById",1); System.out.println("用戶姓名:"+user1.getUsername()); String username = "章卻"; user1.setUsername(username); System.out.println("修改用戶名爲:"+username); sqlSession.update("test" + ".updateUserName",user1); sqlSession.commit(); User user2= sqlSession.selectOne("test.findUserById",1); System.out.println("用戶姓名:"+user2.getUsername()); sqlSession.close(); }
測試結果:
從中能夠看出在查詢緩存數據以前,若是發生了增、刪、改等改變數據的操做,SqlSession類都會清空其一級緩存。mybatis
若是出現沒法使用一級緩存的時候,可使用二級緩存。
二級緩存是Mapper級別的緩存,多個SqlSession類的實例對象操做同一個Mapper配置文件中的SQL語句,多個SqlSession類的實例對象能夠共用二級緩存,二級緩存是以namespace爲單位的,不一樣namespace下的操做互不影響。app
首先開啓二級緩存須要兩步操做,第一步在MyBatis的全局配置文件添加:測試
<setting name="cacheEnabled" value="true" />
而後要在須要開啓二級緩存的具體mapper.xml文件中開啓二級緩存:spa
<cache/>
將要查詢的客戶信息的Java實體類序列化接口:3d
package cn.com.mybatis.po; import java.io.Serializable; import java.util.List; //Serializable接口沒有方法或字段,僅用於標識可序列化的語義 public class Customer implements Serializable{ private int cus_id; private String username; private String acno; private String gender; private String phone; private List<Batch> batchList; //set和get方法省略 }
Customer類實現序列化接口的緣由是,爲了將緩存數據取出來執行反序列化操做,由於二級緩存數據存儲介質多種多樣(如內存、硬盤、服務器),不必定都在內存中。
@Test public void testFindCustomerOnMapper1() throws Exception{ SqlSession sqlSession = dataConnection.getSqlSession(); //獲取Mapper代理 CustomerMapper customerMapper1 = sqlSession.getMapper(CustomerMapper.class); //執行Mapper代理對象的查詢方法 Customer customer1 = customerMapper1.findCustomerById(1); System.out.println("用戶姓名:"+customer1.getUsername() + "|" + "卡號:"+customer1.getAcno()); //獲取Mapper代理 CustomerMapper customerMapper2 = sqlSession.getMapper(CustomerMapper.class); //執行Mapper代理對象的查詢方法 Customer customer2 = customerMapper2.findCustomerById(1); System.out.println("用戶姓名:"+customer2.getUsername() + "|" + "卡號:"+customer2.getAcno()); }
運行測試結果:
當某個Mapper執行了增、刪、改、查的操做時,二級緩存會被清空,以防止數據髒讀。
@Test public void testFindCustomerOnMapper2() throws Exception{ SqlSession sqlSession = dataConnection.getSqlSession(); //獲取Mapper代理 CustomerMapper customerMapper1 = sqlSession.getMapper(CustomerMapper.class); //執行Mapper代理對象的查詢方法 Customer customer1 = customerMapper1.findCustomerById(1); System.out.println("用戶姓名:"+customer1.getUsername() + "|" + "卡號:"+customer1.getAcno()); CustomerMapper customerMapper3 = sqlSession.getMapper(CustomerMapper.class); String AcNo = "3228286666666"; customer1.setAcno(AcNo); customerMapper3.UpdateCustomerAcNo(customer1); System.out.println("修改用戶姓名:" + customer1.getUsername() + "|" +"的卡號爲:"+customer1.getAcno()); sqlSession.commit(); //獲取Mapper代理 CustomerMapper customerMapper2 = sqlSession.getMapper(CustomerMapper.class); //執行Mapper代理對象的查詢方法 Customer customer2 = customerMapper2.findCustomerById(1); System.out.println("用戶姓名:"+customer2.getUsername() + "|" + "卡號:"+customer2.getAcno()); sqlSession.close(); }
運行測試結果:
須要注意,在使用二級緩存時,須要保證該Mapper下的數據不會在其餘Mapper.xml文件中有緩存。好比,在UserMapper.xml中有不少針對user表的操做,可是在一個xxxMapper.xml中,還有針對user單表的操做。這會致使user在兩個命名空間下的緩存數據不一致。若是沒法避免這種狀況的發生,且又須要使用二級緩存,建議使用攔截器判斷執行的SQL涉及哪些表,而後把相關表的緩存清空。