1. 程式人生 > 實用技巧 >【MyBatis】MyBatis 快取

【MyBatis】MyBatis 快取

MyBatis 快取

文章原始碼

什麼是快取

像大多數的持久化框架一樣,MyBatis 也提供了快取策略,通過快取策略來減少資料庫的查詢次數,從而提高效能。

Mybatis 中快取分為一級快取,二級快取。

快取的適用範圍

適用範圍:

  • 經常查詢並且不經常改變的
  • 資料的正確與否對最終結果影響不大

一級快取

它指的是 MyBatis 中 SqlSession 物件的快取,當執行查詢之後,查詢的結果會同時存入到 SqlSession 會提供一塊區域。該區域的結構是一個 Map,當再次查詢同樣的資料,MyBatis 會先去 SqlSession 中查詢是否存在,如果有則直接拿出來使用。

當 SqlSession 物件消失時,MyBatis 的一級快取也就消失了。

一級快取的使用

  • 編寫使用者持久層 DAO 介面

        /**
        * 根據 ID 查詢操作,使用一級快取
        * @param id
        * @return
        */
        User findByIdCache(Integer id);
    
  • 編寫使用者持久層對映檔案

        <select id="findByIdCache" resultType="USER" parameterType="java.lang.Integer">
            select * from user where id = #{id};
        </select>
    
  • 測試

        @Test
        public void findByIdCacheTest() {
            User user1 = userDAO.findByIdCache(41);
            System.out.println(user1.hashCode());  // 1439337960
            User user2 = userDAO.findByIdCache(41);
            System.out.println(user2.hashCode());  // 1439337960
    
            System.out.println(user1 == user2); // true
        }
    

一級快取的清空

    @Test
    public void findByIdCacheClearTest() {
        User user1 = userDAO.findByIdCache(41);
        System.out.println(user1.hashCode());  // 1439337960

        // 使快取消失方法一:關閉 SqlSession 物件
        // session.close();

        // 使快取消失方法二
        session.clearCache();

        // session = factory.openSession();
        userDAO = session.getMapper(UserDAO.class);

        User user2 = userDAO.findByIdCache(41);
        System.out.println(user2.hashCode());  // 315860201

        System.out.println(user1 == user2); // false
    }

一級快取的分析

  • 一級快取是 SqlSession 範圍的快取,當呼叫 SqlSession 的修改,新增,刪除,commit()close() 等方法時,就會清空一級快取。
  • 第一次發起查詢使用者 id 為 41 的使用者資訊,先去找快取中是否有 id 為 41 的使用者資訊,如果沒有,從資料庫查詢使用者資訊。
  • 得到使用者資訊,將使用者資訊儲存到一級快取中。
  • 如果 SqlSession 去執行 commit 操作(執行插入、更新、刪除),清空 SqlSession 中的一級快取,這樣做的目的為了讓快取中儲存的是最新的資訊,避免髒讀
  • 第二次發起查詢使用者 id 為 41 的使用者資訊,先去找快取中是否有 id 為 41 的使用者資訊,快取中有,直接從快取中獲取使用者資訊。

二級快取

它指的是 MyBatis 中 SqlSessionFactory 物件的快取,由同一個 SqlSessionFactory 物件建立的 SqlSession 共享其快取。

二級快取結構圖

二級快取的使用

  • 在 SqlMapConfig.xml 檔案開啟二級快取

    <settings>
            <!-- 開啟二級快取的支援 -->
            <setting name="cacheEnabled" value="true"/>
        </settings>
    
  • 配置相關的 Mapper 對映檔案

        <!-- 開啟二級快取的支援 -->
        <cache></cache>
    
  • 配置 statement 上面的 useCache 屬性

        <select id="findByIdHighCache" resultType="USER" parameterType="java.lang.Integer" useCache="true">
            select * from user where id = #{id};
        </select>
    
  • 測試

        @Test
        public void findByIdHighCacheTest() {
            SqlSession sqlSession1 = factory.openSession();
            UserDAO dao1 = sqlSession1.getMapper(UserDAO.class);
            User user1 = dao1.findByIdHighCache(41);
            System.out.println(user1.hashCode());   // 765284253
            sqlSession1.close();    // 一級快取消失
    
            SqlSession sqlSession2 = factory.openSession();
            UserDAO dao2 = sqlSession2.getMapper(UserDAO.class);
            User user2 = dao2.findByIdHighCache(41);
            System.out.println(user2.hashCode());   // 1043351526
            sqlSession1.close();    // 一級快取消失
    
            System.out.println(user1 == user2); // false
    
        }
    

測試中執行了兩次查詢,並且在執行第一次查詢後,關閉了一級快取,再去執行第二次查詢時,可以發現並沒有對資料庫發出 SQL 語句,所以此時的資料就只能是來自於所說的二級快取。

練習和總結