Mybatis的一級緩存和二級緩存的理解以及用法

  • 2019 年 10 月 3 日
  • 筆記

  程序中為什麼使用緩存?
  先了解一下緩存的概念:原始意義是指訪問速度比一般隨機存取存儲器快的一種RAM,通常它不像系統主存那樣使用DRAM技術,而使用昂貴但較快速的SRAM技術。對於我們編程來說,所謂的緩存,就是將程序
或系統經常要調用的對象(臨時數據)存在內存中,一遍其使用時可以快速調用,不必再去創建新的重複的實例。這樣做可以減少系統的開銷,提高效率。
  對緩存有了一定的了解以後就知道了使用緩存是為了減少和數據庫的交互次數,提高執行效率。那麼下一個問題來了。什麼樣的數據能使用緩存,什麼樣的數據不能使用?
  這是我們使用緩存必須要明確的事情,實際上適用於緩存的數據:經常查詢並且不經常改變的,並且的數據的正確與否對最終結果影響不大的、不適用於緩存的數據:經常改變的數據,數據的正確與否對最終
結果影響很大的。
  Mybatis中的一級緩存和二級緩存到底緩存了什麼,緩存了以後又有什麼效果,緩存的數據什麼時候會被清空?
  一級緩存:它指的是Mybatis中sqlSession對象的緩存,當我們執行查詢以後,查詢的結果會同時存入到SqlSession為我們提供的一塊區域中,該區域的結構是一個Map,當我們再次查詢同樣的數據,mybatis會
先去sqlsession中查詢是否有,的話直接拿出來用,當SqlSession對象消失時,mybatis的一級緩存也就消失了,同時一級緩存是SqlSession範圍的緩存,當調用SqlSession的修改、添加、刪除、commit(),close等
方法時,就會清空一級緩存。
  二級緩存:他值得是Mybatis中SqlSessionFactory對象的緩存,由同一個SqlSessionFactory對象創建的SqlSession共享其緩存,但是其中緩存的是數據而不是對象,所以從二級緩存再次查詢出得結果的對象與
第一次存入的對象是不一樣的。
  通過簡單的例子來加深理解一級緩存和二級緩存。

 一級緩存

  1.用戶類

public class User implements Serializable{      private Integer id;      private String username;      private Date birthday;      private String sex;      private String address;        get和set方法省略.....  }

    2.Dao層

public interface UserDao {      /**       * 查詢所有的用戶       *       * @return       */      List<User> findAll();      /**       * 根據Id查詢用戶       *       * @return       */      User findById(Integer id);      /**       * 更新用戶       * @param user       */      void updateUser(User user);  }

  3.UserDao.xml映射文件

<mapper namespace="com.example.dao.UserDao">      <select id="findAll" resultType="com.example.domain.User">          SELECT * FROM USER;      </select>      <select id="findById" resultType="com.example.domain.User" parameterType="INT">          SELECT * FROM  USER  WHERE ID = #{ID}      </select>      <update id="updateUser" parameterType="com.example.domain.User">          update USER          <set>              <if test="username != null">username=#{username},</if>              <if test="password != null">birthday=#{birthday},</if>              <if test="sex != null">sex=#{sex},</if>              <if test="address != null">address=#{address},</if>          </set>          where id=#{id}      </update>  </mapper>

  在以上三步中這是mybatis的單表操作,下面通過根據用戶ID查詢用戶的操作來觀察一級緩存生效與否的區別  

  4.測試
    (1)  命中一級緩存的情況
    測試代碼:

@Test      public void findByIdTest(){          session = factory.openSession();          userDao = session.getMapper(UserDao.class);          //第一次獲取該用戶          User user1 = userDao.findById(45);          System.out.println(user1);          第二次獲取該用戶          User user2 = userDao.findById(45);          System.out.println(user2);          System.out.println(user1 == user2);          session.close();      }  

測試結果:

  

  (2)對SqlSession進行清除緩存的操作,即清楚一級緩存,然後再次進行測試。

 @Test      public void findByIdTest(){          session = factory.openSession();          userDao = session.getMapper(UserDao.class);          User user1 = userDao.findById(45);          System.out.println(user1);   //       session.commit(); 調用SqlSession的commit方法清空緩存            user1.setUsername("更新用戶");          user1.setAddress("更新地址");          userDao.updateUser(user1);//通過更新SqlSession清空緩存          User user2 = userDao.findById(45);          System.out.println(user2);          System.out.println(user1 == user2);          session.close();      }

  清空緩存的操作很多,可以都試試。測試結果:

  二級緩存  

  再看一下Mybatis二級緩存是如何使用的,第一步讓Mybatis框架支持二級緩存(在Mybatis的主配置文件中配置),第二步讓當前的映射文件支持二級緩存(在Dao.xml映射文件中配置),第三步讓當前的方法支持二級緩存(在標籤中配置)。根據這個步驟將上面的查詢用戶的接口通過配置改造為可以支持二級緩存的方法。
  1.配置Mybatis框架支持二級緩存

<setting name="cacheEnabled" value="true"/>

  2.配置UserDao.xml支持二級緩存

 <cache/>

  3.配置查詢的方法支持二級緩存

<select id="findById" resultType="com.example.domain.User" parameterType="INT" useCache="true">          SELECT * FROM  USER  WHERE ID = #{ID}     </select>

  4.測試

@Test      public void findByIdTest(){          //第一次查詢 並更新二級緩存          SqlSession session1 = factory.openSession();          UserDao userDao1 = session1.getMapper(UserDao.class);          User user1 = userDao1.findById(45);          System.out.println(user1);          session1.commit(); //commit()方法提交二級緩存 同時清空一級緩存          session1.close();//    //        user1.setUsername("更新用戶");  //        user1.setAddress("更新地址");  //        userDao.updateUser(user1);//通過更新SqlSession清空緩存          //第二次查找命中二級緩存          SqlSession session2 = factory.openSession();          UserDao userDao2 = session2.getMapper(UserDao.class);          User user2 = userDao2.findById(45);          session2.commit(); //commit()方法提交二級緩存 同時清空一級緩存          session2.close();//          System.out.println(user2);          System.out.println(user1 == user2);      }

  測試結果:

 

 總結:mybatis的的一級緩存是SqlSession級別的緩存,一級緩存緩存的是對象,當SqlSession提交、關閉以及其他的更新數據庫的操作發生後,一級緩存就會清空。二級緩存是SqlSessionFactory級別的緩存,同一個SqlSessionFactory產生的SqlSession都共享一個二級緩存,二級緩存中存儲的是數據,當命中二級緩存時,通過存儲的數據構造對象返回。查詢數據的時候,查詢的流程是二級緩存>一級緩存>數據庫