MyBatis的緩存指的是緩存查詢結果,當之後使用相同的sql語句、傳入相同的參數進行查詢時,可直接從mybatis本地緩存中獲取查詢結果,而沒必要查詢數據庫。sql
mybatis的緩存包括一級緩存、二級緩存,一級緩存默認是開啓的,二級緩存默認是關閉的。數據庫
一級緩存:緩存
SqlSession級別,在SqlSession中有一個Map,key是由sql語句、參數等信息組成的惟一值,value是查詢出來的結果對象。mybatis
二級緩存:app
mapper級別,同一個namespace下的mapper,有一個Map。spa
二級緩存能夠使這些sqlSession作到查詢結果共享。code
一級緩存默認是開啓的。xml
User user1 = mapper.queryUserById(1); User user2 = mapper.queryUserById(1);
第一次查詢時,就將查詢結果放到一級緩存中。對象
若是後續使用的sql語句相同、傳入的實參也相同,則結果對象也會相同,直接從一級緩存中獲取結果對象,再也不查詢數據庫。blog
User user1 = mapper.queryUserById(1); sqlSession.commit(); User user2 = mapper.queryUserById(1);
若是此sqlSession調用了commit()方法,會自動清空此sqlSession的一級緩存。
由於使用commit(),會將修改提交到數據庫,下一次相同的查詢,查詢結果可能變了,以前的一級緩存不能再用,因此會自動清空。
User user1 = mapper.queryUserById(1); HashMap<String, Object> map = new HashMap<>(); map.put("username", "張三"); map.put("id", 1); mapper.updateUser(map); User user2 = mapper.queryUserById(1);
事實上,只要此sqlSession調用了<update>、<insert>、<delete>這些會修改數據庫的元素,就會清空此sqlSession的一級緩存,無論有沒有使用commit()提交。
SqlSession sqlSession1 = MyBatisUtils.getSqlSession(); UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class); User user1 = mapper1.queryUserById(1); System.out.println(user1); SqlSession sqlSession2 = MyBatisUtils.getSqlSession(); UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); User user2 = mapper2.queryUserById(1); System.out.println(user2);
不使用二級緩存,會執行2次查詢。
二級緩存的使用步驟,此處以UserMapper爲例:
public class User implements Serializable { //...... }
<settings>
<setting name="logImpl" value="LOG4J"/>
<setting name="cacheEnabled" value="true"/>
</settings>
二級緩存默認是關閉的,須要手動開啓。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.chy.mapper.UserMapper"> <cache /> <select id="queryUserById" parameterType="integer" resultType="user"> SELECT * FROM user_tb WHERE id=#{id} </select> <update id="updateUser" parameterType="hashmap"> UPDATE user_tb SET username=#{username} WHERE id=#{id} </update> </mapper>
完整寫法:
<cache type="perpetualCache" />
type指定二級緩存的實現方式,缺省type時默認使用mybatis自帶的perpetualCache。
SqlSession sqlSession1 = MyBatisUtils.getSqlSession(); UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class); User user1 = mapper1.queryUserById(1); System.out.println(user1); sqlSession1.close(); SqlSession sqlSession2 = MyBatisUtils.getSqlSession(); UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); User user2 = mapper2.queryUserById(1); System.out.println(user2);
只執行1次查詢。後續使用相同sql語句、傳入相同的實參進行查詢時,直接從二級緩存中獲取結果對象。
提交修改時,會清空整個二級緩存:
SqlSession sqlSession1 = MyBatisUtils.getSqlSession(); UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class); User user1 = mapper1.queryUserById(1); System.out.println(user1); HashMap<String, Object> hashMap = new HashMap<>(); hashMap.put("username", "j"); hashMap.put("id", 1); mapper1.updateUser(hashMap); sqlSession1.commit(); SqlSession sqlSession2 = MyBatisUtils.getSqlSession(); UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); User user2 = mapper2.queryUserById(2); System.out.println(user2);
只寫了commit()、實際沒有調用<insert> | <update> | <delete>,不會清空二級緩存,反而會將以前查詢結果寫入到二級緩存。
寫了commit()、有調用<insert> | <update> | <delete>,會清空整個二級緩存。
前後調用commit()、close(),不會寫入二級緩存,由於commit()的存在,反而會清空整個二級緩存。