1. 程式人生 > >Mybatis的一級快取和二級快取的理解以及用法

Mybatis的一級快取和二級快取的理解以及用法

  程式中為什麼使用快取?
  先了解一下快取的概念:原始意義是指訪問速度比一般隨機存取儲存器快的一種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都共享一個二級快取,二級快取中儲存的是資料,當命中二級快取時,通過儲存的資料構造物件返回。查詢資料的時候,查詢的流程是二級快取>一級快取>資料庫。<