Mybatis一級、二級緩衝,mybatis二級緩衝

來源:互聯網
上載者:User

Mybatis一級、二級緩衝,mybatis二級緩衝
一級緩衝

首先做一個測試,建立一個mapper設定檔和mapper介面,我這裡用了最簡單的查詢來示範。

<mapper namespace="cn.elinzhou.mybatisTest.mapper.UserMapper">    <select id="findUsers" resultType="cn.elinzhou.mybatisTest.pojo.User">        SELECT * FROM user    </select></mapper>
public interface UserMapper {    List<User> findUsers()throws Exception;}

然後編寫一個單元測試

public class UserMapperTest {    SqlSession sqlSession = null;    @Before    public void setUp() throws Exception {        // 通過設定檔擷取資料庫連接資訊        Reader reader = Resources.getResourceAsReader("cn/elinzhou/mybatisTest/config/mybatis.xml");        // 通過配置資訊構建一個SqlSessionFactory        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);        // 通過sqlSessionFactory開啟一個資料庫會話        sqlSession = sqlSessionFactory.openSession();    }    @Test    public void testFindUsers() throws Exception {        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);        List<User> users = userMapper.findUsers();        System.out.println(users);    }}

運行,可以看到控制台輸出(先配好log4j)為類似如日誌

日誌說明了該操作執行的sql語句已經查詢的內容,最後一行是我手動通過System.out.printf輸出的結果。

然後再加一條語句

users = userMapper.findUsers();

之前的單元測試就變成了這個樣子

也就是在執行完userMapper.findUsers();後立刻再執行一遍userMapper.findUsers(); 可以想象,其實這兩個操作執行的sql是完全相同的,而且在這期間沒有對資料庫進行過其他動作。然後執行該單元測試,發現效果跟上面執行一條的時候完全相同,也就是執行第二次userMapper.findUsers();操作的時候沒有對資料庫進行查詢,那麼得到的資料是從哪裡來的?答案是一級緩衝。

mybatis一級緩衝是指在記憶體中開闢一塊地區,用來儲存使用者對資料庫的操作資訊(sql)和資料庫返回的資料,如果下一次使用者再執行相同的請求,那麼直接從記憶體中讀數資料而不是從資料庫讀取。
其中資料的生命週期有兩個影響因素。

對sqlsession執行commit操作,也就意味著使用者執行了update、delete等操作,那麼資料庫中的資料勢必會發生變化,如果使用者請求資料仍然使用之前記憶體中的資料,那麼將讀到髒資料。所以在執行sqlsession操作後,會清除儲存資料的HashMap,使用者在發起查詢請求時就會重新讀取資料並放入一級緩衝中了。

上述測試就是在第一查詢完後執行了commit操作,再進行查詢。與之前的測試不同的是,這次測試控制台列印了兩組查詢結果,說明在commit之後mybatis對資料重新進行了查詢。

一般在mybatis整合spring時,會把SqlSessionFactory設定為單例注入到IOC容器中,不把sqlsession也設定為單例的原因是sqlsession是線程不安全的,所以不能為單例。那也就意味著其實是有關閉sqlsession的過程的。其實,對於每一個service中的sqlsession是不同的,這是通過mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer建立sqlsession自動注入到service中的。
而一級緩衝的設計是每個sqlsession單獨使用一個緩衝空間,不同的sqlsession是不能互相訪問資料的。當然,在sqlsession關閉後,其中資料自然被清空。

二級緩衝

在使用二級緩衝之前,先測試之前提到過的關閉sqlsession後會清空緩衝的問題,把junit代碼修改一下

@Test    public void testFindUsers() throws Exception {        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);        List<User> users = userMapper.findUsers();        //關閉sqlsession        sqlSession.close();        //通過sqlsessionFactroy建立一個新的sqlsession        sqlSession = sqlSessionFactory.openSession();        //擷取mapper對象        userMapper = sqlSession.getMapper(UserMapper.class);        users = userMapper.findUsers();        System.out.println(users);    }

這段代碼在第一次查詢完後關閉sqlsession,然後建立新的sqlsession和mapper來重新執行一次查詢操作,可以預見,執行結果

說明關閉了sqlsession後的確把之前的快取資料清空了,之後再執行同樣的查詢操作也會再訪問一遍資料庫。為瞭解決這個問題,需要使用二級緩衝

一級緩衝的範圍僅限於一個sqlsession,但是二級緩衝的範圍是一個namespace。但並不是意味著同一個namespace建立的mapper可以互相讀取緩衝內容,這裡的原則是,如果開啟了二級緩衝,那麼在關閉sqlsession後,會把該sqlsession一級緩衝中的資料添加到namespace的二級緩衝中。

接下測試,先需要開啟二級緩衝。

1.開啟二級緩衝總開關
開啟總開關,只需要在mybatis總設定檔中加入一行設定

<settings>   <!--開啟二級緩衝-->    <setting name="cacheEnabled" value="true"/></settings>

2.開啟需要使用二級緩衝的mapper的開關

在需要開啟二級緩衝的mapper.xml中加入caceh標籤

<cache/>

3.POJO序列化

讓需要使用二級緩衝的POJO類實現Serializable介面,如

public class User implements Serializable {

通過之前三步操作就可以使用二級緩衝了,接下來測試。添加一個Junit方法

@Test    public void testFindUsersCache() throws Exception {        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);        List<User> users = userMapper.findUsers();        //關閉sqlsession        sqlSession.close();        //通過sqlsessionFactroy建立一個新的sqlsession        sqlSession = sqlSessionFactory.openSession();        //擷取mapper對象        userMapper = sqlSession.getMapper(UserMapper.class);        users = userMapper.findUsers();        System.out.println(users);    }

執行後可以發現,控制台值輸出了一次查詢過程,也可以證明二級緩衝開啟成功。

還有一個問題,之前說了,即使開啟了二級緩衝,不同的sqlsession之間的快取資料也不是想互訪就能互訪的,必須等到sqlsession關閉了以後,才會把其一級緩衝中的資料寫入二級緩衝。為了測試這個,把上述代碼中的

sqlSession.close();

注釋,那麼之前的代碼就變成了

再執行,發現控制太又輸出了兩次的查詢過程,所以可以印證,只有關閉了sqlsession之後,才會把其中一級快取資料寫入二級緩衝。

緩衝配置
  • 關閉重新整理

在預設情況下,當sqlsession執行commit後會重新整理緩衝,但是也可以強制設定為不重新整理,在不需要重新整理的標籤中加入

flushCache="false" 

<select id="findUsers" resultType="cn.elinzhou.mybatisTest.pojo.User" flushCache="false">

那麼,無論是否執行commit,緩衝都不會重新整理了。但是這樣會造成髒讀,只有在特殊情況下才使用

  • 自動重新整理

有些情況下,需要設定自動重新整理緩衝,那麼需要配置對應mapper中的cache標籤。

flushInterval="10000"

該屬性工作表示每隔10秒鐘自動重新整理一遍緩衝

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.