MyBatis的緩存指的是緩存查詢結果,當以後使用相同的sql語句、傳入相同的參數進行查詢時,可直接從mybatis本地緩存中獲取查詢結果,而不必查詢資料庫。 mybatis的緩存包括一級緩存、二級緩存,一級緩存預設是開啟的,二級緩存預設是關閉的。 一級緩存: SqlSession級別,在SqlSe ...
MyBatis的緩存指的是緩存查詢結果,當以後使用相同的sql語句、傳入相同的參數進行查詢時,可直接從mybatis本地緩存中獲取查詢結果,而不必查詢資料庫。
mybatis的緩存包括一級緩存、二級緩存,一級緩存預設是開啟的,二級緩存預設是關閉的。
一級緩存:
SqlSession級別,在SqlSession中有一個Map,key是由sql語句、參數等信息組成的唯一值,value是查詢出來的結果對象。
二級緩存:
mapper級別,同一個namespace下的mapper,有一個Map。
二級緩存可以使這些sqlSession做到查詢結果共用。
一級緩存
一級緩存預設是開啟的。
User user1 = mapper.queryUserById(1);
User user2 = mapper.queryUserById(1);
第一次查詢時,就將查詢結果放到一級緩存中。
如果後續使用的sql語句相同、傳入的實參也相同,則結果對象也會相同,直接從一級緩存中獲取結果對象,不再查詢資料庫。
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為例:
(1)pojo類要是可序列化的
public class User implements Serializable { //...... }
(2)在mybatis全局配置文件中開啟二級緩存
<settings>
<setting name="logImpl" value="LOG4J"/>
<setting name="cacheEnabled" value="true"/>
</settings>
二級緩存預設是關閉的,需要手動開啟。
(3)在mapper映射文件中指定二級緩存的實現方式,必須顯式指定
<?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。
(4)需要調用close()關閉sqlSession,才會將此sqlSession的查詢結果(一級緩存)寫入到二級緩存中
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()的存在,反而會清空整個二級緩存。