程序中為什么使用緩存?
實際上適用於緩存的數據:經常查詢並且不經常改變的,並且的數據的正確與否對最終結果影響不大的、不適用於緩存的數據:經常改變的數據,數據的正確與否對最終
結果影響很大的。
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都共享一個二級緩存,二級緩存中存儲的是數據,當命中二級緩存時,通過存儲的數據構造對象返回。查詢數據的時候,查詢的流程是二級緩存>一級緩存>數據庫。