MyBatis緩存結構

咱們能夠將一些變更不大且訪問頻率高的數據,放置在一個緩存容器中,用戶下一次查詢時就從緩存容器中獲取結果。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();  
}

查看運行結果:
image.png
從圖中能夠看出第一次查詢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();  
}

測試結果:
image.png
從中能夠看出在查詢緩存數據以前,若是發生了增、刪、改等改變數據的操做,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());  
  
}

運行測試結果:
image.png

驗證二級緩存清空

當某個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();  
}

運行測試結果:
image.png

須要注意,在使用二級緩存時,須要保證該Mapper下的數據不會在其餘Mapper.xml文件中有緩存。好比,在UserMapper.xml中有不少針對user表的操做,可是在一個xxxMapper.xml中,還有針對user單表的操做。這會致使user在兩個命名空間下的緩存數據不一致。若是沒法避免這種狀況的發生,且又須要使用二級緩存,建議使用攔截器判斷執行的SQL涉及哪些表,而後把相關表的緩存清空。

相關文章
相關標籤/搜索