MyBatis延遲加載,一級緩存,二級緩存
延遲加載配置:
什麼時候用延遲加載?比如現在有班級和學生表,一對多關係,你可能只需要班級的信息,而不需要該班級學生的信息,這時候可以進行配置,讓查詢時先查詢到班級的信息,在之後需要學生信息時候,再進行查詢,避免不必要的查詢。
需要進行如下配置:這裏以一對多爲例,其他關係類似:
PersonMapping.xml
<select id="selectPersonByClassId" resultMap="class_person_map" parameterType="int">
select * from class where classId=#{id}
</select>
<resultMap id="class_person_map" type="class">
<id column="classId" property="classId"/>
<result property="number" column="number"/>
<collection property="persons" ofType="person" select="mappers.ClassMapper.queryPersonByClassId" column="classId">
</collection>
</resultMap>
注意我們的映射,只映射了班級id和班級Number兩個信息,並沒有映射學生信息,而是通過<cllection>來配置的,標籤屬性
select:當需要persons屬性時,執行select值所對應的id的sql語句進行查詢(mappers.ClassMapper,xml)
column:執行sql語句時傳入的參數
mappers.ClassMapper.xml
當需要班級學生信息時,會通過select屬性來尋找到指定id的sql語句查詢,如下
<select id="queryPersonByClassId" parameterType="int" resultType="Person">
select * from person where classId=#{classid}
</select>
之後設置斷點調試可以看到只有調用了Class.getPersons()方法纔會執行查詢學生的sql語句。
一級緩存:
當通過一個SqlSession對象查詢到一個數據時,MyBatis會將該數據放入該sqlsession當中,當下一次再次查詢該數據時,會從該sqlsession直接取得該數據,不需要再與數據庫交互查詢,自動開啓。不過注意第二次查詢必須也是在同一個SQLSESSION之下進行的。
二級緩存:
myBatis內置的:
接上面,通過一個SQLSession對象查詢到了一個數據,不僅會放入一級緩存,還會放入二級緩存當中。當你下一次通過另一個不同的SQLSEssion對象查詢相同的數據時,會從二級緩存當中進行獲取,不過查詢時SQLSession必來自同一個mapper.class。
總的來說兩句話:一級緩存同一個sqlsession,二級緩存同一個mapper.class初始化的,即同一個namespace,是否進入緩存就是依據這個判斷的。
開啓配置方式:
config.xml:
<setting name="cacheEnabled" value="true"/>
mapper,xml
<cache/>
另外二級緩存是將數據進行序列化的,所以必要要讓開啓二級緩存的對象繼承序列化接口才行。序列化就是將數據從內存放入到硬盤之中。
即給mapper.xml對應的指定class 加上
implements Serializable
而且如果當前mapper對應的class繼承了其他類或者裏面有級聯屬性,其他類或者級聯屬性也必須要序列化。
相當於序列化三個:本類,父類,級聯屬性
一級緩存二級緩存的緩存時機:
一級緩存只要查詢了就放入一級緩存當中,相當於是實時的,
二級緩存是在一個sqlsession.close()之後纔會將該sqlsession所查詢到的放入到二級緩存當中。
示例:
//加載配置信息
Reader reader = Resources.getResourceAsReader("config.xml");
//connection
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//第一個sqlsession
SqlSession sqlSession = sessionFactory.openSession();
PersonMapping personMapping = sqlSession.getMapper(PersonMapping.class);
personMapping.selectPersonById(2);
System.out.println("---");
sqlSession.close();
//第二個sqlsession
SqlSession sqlSession2 = sessionFactory.openSession();
PersonMapping personMapping2 = sqlSession2.getMapper(PersonMapping.class);
personMapping2.selectPersonById(2);
sqlSession2.close();
執行後,查看日誌可以看到只執行了一條sql語句,PersonMapping.class共享同一個二級緩存
清理緩存:commit()會清除緩存(一級二級都是的),另外注意這個commit()不能是查詢自身的commit,即這個commit所屬於的sqlsession對象必須是執行了增刪改的sqlsession。