延遲加載就是在需要用到數據的時候才進行加載,不需要用到數據的時候就不加載數據。延遲加載也稱爲懶加載。
優點:在使用關聯對象時,才從數據庫中查詢關聯數據,大大降低數據庫不必要開銷。
缺點:因爲只有當需要用到數據時,纔會進行數據庫查詢,這樣在大批量數據查詢時,因爲查詢工作也需要耗費時間,所以可能造成用戶等待時間變長,造成用戶體驗下降。
數據庫模型準備
下面我們給出的就是一個數據庫關係模型,在後面的例子中一這兩個表爲基礎講解MyBatis延遲加載。我們假定Article(文章)與Tag(標籤)是一對多的關係。
注意面這段話的表述:表的關聯關係大致可以分爲四種:一對一、多對一、一對多、多對多,但是實質上從單獨一個表的角度上來看只存在一對一和一對多關係;而一對一和一對多的關係都能通過下列兩個表來表示,以Article表的角度上來看,一個Article數據可以由多個Tag數據行對應,這就是一對多的關係;而一個Tag數據只能與一個Article關聯,這就是一對一的關係。所以瞭解了MyBatis一對多的延遲加載的配置(雙向)也就學會了四種關聯模式的配置。
第一步:配置MyBatis核心配置文件
如果想使用延遲加載策略,就需要在MyBatis全局配置文件中開啓延遲加載策略:
參數詳情參考官方文檔:settings配置
我們在MyBatis全局配置文件(SqlMapConfig.xml)中添加下列代碼:
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
</settings>
第二步:配置映射文件
預先定義ArticleMapper和TagMapper接口
ArticleMapper接口:
public interface ArticleMapper {
Article getArticleById(Long id);
}
TagMapper接口:
public interface TagMapper {
Tag getTagById(Long id);
Tag getTagsByArticleId(Long id);
}
配置ArticleMapper.xml映射文件(一對多配置)
在不使用延遲加載的情況下,我們通常使用的是關聯查詢,直接查出關聯對象的數據:
<mapper namespace="com.tjd.spring_mybatis_plus.mapper.ArticleMapper">
<resultMap id="articleMap" type="Article">
<id column="id" property="id"></id>
<result column="title" property="title"></result>
<result column="content" property="content"></result>
<collection property="tags" ofType="Tag">
<id column="tid" property="id"></id>
<result column="tcontent" property="content"></result>
</collection>
</resultMap>
<select id="getArticleById" resultMap="articleMap" parameterType="long">
SELECT
a.id id,
a.title title,
a.content content,
t.id tid,
t.content tcontent
FROM
article a
LEFT JOIN tag t ON a.id = t.article_id
WHERE
a.id = #{id}
</select>
</mapper>
如果要想使用延遲加載策略,那麼映射文件配置就不能採用連接查詢了,因爲這樣一旦SQL語句執行了,關聯數據也就查詢出來了
,所以我們要將原來的關聯查詢,轉換成單表查詢:
<mapper namespace="com.tjd.spring_mybatis_plus.mapper.ArticleMapper">
<resultMap id="articleMap" type="Article">
<id column="id" property="id"></id>
<result column="title" property="title"></result>
<result column="content" property="content"></result>
<collection property="tags" ofType="Tag" column="id" select="com.tjd.spring_mybatis_plus.mapper.TagMapper.getTagsByArticleId" ></collection>
</resultMap>
<select id="getArticleById" resultMap="articleMap" parameterType="long">
select * from article where id=#{id}
</select>
</mapper>
collection標籤屬性:
- ofType:用於指定集合元素的數據類型。
- select:指定用於查詢關聯表數據SQL語句的ID。
- column:是用於指定使用哪個字段的值作爲條件查詢。
在TagMapper.xml映射文件中定義如下語句:
<!--在前面定義的ArticleMapper.xml映射文件中collection標籤中select屬性就是指向的這個SQL語句-->
<select id="getTagsByArticleId" parameterType="long" resultType="Article">
select * from tag where article_id=#{article_id}
</select>
做到這裏,一對多的延遲加載配置就完成了,在執行ArticleMapper中ID爲getArticleById的SQL語句時,並不會立即執行TagMapper中的getTagsByArticleId,而是在需要時再執行getTagsByArticleId,從而達到了延遲加載的目的。
配置TagMapper.xml映射文件(一對一 或 多對一 配置)
<mapper namespace="com.tjd.spring_mybatis_plus.mapper.TagMapper">
<resultMap id="tagMap" type="Tag">
<id column="id" property="id"></id>
<result column="content" property="content"></result>
<association property="article" column="article_id" javaType="Article" select="com.tjd.spring_mybatis_plus.mapper.ArticleMapper.getArticleById"></association>
</resultMap>
<!--並沒有採用關聯查詢-->
<select id="getTagById" parameterType="long" resultMap="tagMap">
select * from tag where id=#{id}
</select>
<select id="getTagsByArticleId" parameterType="long" resultMap="Article">
select * from tag where article_id=#{article_id}
</select>
</mapper>
association標籤屬性:
- ofType:用於指定集合元素的數據類型。
- select:指定用於查詢關聯表數據SQL語句的ID。
第三步:測試
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class LazyLoadTest {
@Autowired
private ArticleMapper articleMapper;
@Autowired
private TagMapper tagMapper;
@Test
public void test(){
Tag tag = tagMapper.getTagById(1L);
Article article = tag.getArticle();
List<Tag> tags = article.getTags();
}
}
如果想要驗證延遲加載策略,我們推薦採用Debug,開啓MyBatis SQL日誌功能,然後每執行一條語句就會發現控制檯輸出一條SQL語句,這就表明它的關聯數據是延遲查詢的。