Mybatis中的兩種級聯方式

Mybatis中的兩種級聯方式

最近在做一個基於SpringBoot+MybatisPlus博客系統的項目,在管理後臺需要列出所有文章,效果是這樣的:

avatar

注意紅色部分,查出文章的信息時,還需要查文章的分類和文章的標籤。這很容易想到需要使用Mybatis的級聯查詢,但是在寫mapper文件代碼的時候,想到級聯其實有兩種方式:

  • 基於分層次查詢的
  • 基於SQL表連接的

這樣說,大家可能會覺得雲裏霧裏的,啥叫分層次的,啥又叫SQL表連接的,這裏給出代碼,想必平時使用過Mybatis的小夥伴就會明白了。

  • 基於分層次查詢的
<resultMap id="resultMap1" type="site.alanliang.geekblog.domain.Article">
    <id property="id" column="id"/>
    <result property="title" column="title"/>
    
    <association property="category" column="category_id" select="site.alanliang.geekblog.mapper.ArticleMapper.selectCategoryById"/>
    
</resultMap>

<select id="selectCategoryById" resultType="site.alanliang.geekblog.domain.Category">
    select id, name from t_category where id = #{id}
</select>

<select id="selectArticleById1" parameterType="long" resultMap="resultMap1">
    select id, title, category_id from t_article where id = #{id}
</select>
  • 基於SQL表連接的
<resultMap id="resultMap2" type="site.alanliang.geekblog.domain.Article">
    <id property="id" column="id"/>
    <result property="title" column="title"/>
    
    <association property="category" javaType="site.alanliang.geekblog.domain.Category">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
    </association>
    
</resultMap>

<select id="selectArticleById2" parameterType="long" resultMap="resultMap2">
    select ta.id, ta.title, tc.id, tc.name
    from t_article ta
    inner join t_category tc
    on ta.category_id = tc.id
    where ta.id = #{aid}
</select>

注意association和select標籤的區別。我平時比較粗心,根本沒在意它們的區別,但是這次做項目的時候再次碰到,這次才引起了我的注意,也激起了我的好奇心,究竟它們的區別在哪呢?

查過資料後,我終於明白了:

分層次查詢的方式是單表查詢,首先發送1條SQL查詢文章(Article)的信息,然後查詢文章的分類(category)時再發送1條SQL,也就是查詢1條文章記錄需要發送2條SQL。

基於SQL表連接的方式是多表查詢,在這裏也就是Article表和Category表連接查詢,只需要發送1條SQL。

我們做個測試,測試代碼如下:

@Autowired
private ArticleMapper articleMapper;

@Test
void selectArticleById1(){
    Article article = articleMapper.selectArticleById1(7L);
    System.out.println(article);
}

@Test
void selectArticleById2(){
    Article article = articleMapper.selectArticleById2(7L);
    System.out.println(article);
}

測試結果如下:

avatar

avatar

結果顯而易見。

過程分析

  • 基於分層次查詢

我認爲的大致過程是這樣的。首先,測試中執行代碼:

 Article article = articleMapper.selectArticleById1(7L);

Mybatis會找到相應mapper文件中的這部分代碼:

<select id="selectArticleById1" parameterType="long" resultMap="resultMap1">
    select id, title, category_id from t_article where id = #{id}
</select>

Mybatis發送完這條SQL語句,查詢到字段id,title和category_id。將字段id和title映射至resultMap1中的相應屬性,category_id後面會用到(注意!SQL語句中不能缺少這個字段,否則將查不到對應的category)而resultMap1中代碼:

<resultMap id="resultMap1" type="site.alanliang.geekblog.domain.Article">
    <id property="id" column="id"/>
    <result property="title" column="title"/>
    
    <association property="category" column="category_id" select="site.alanliang.geekblog.mapper.ArticleMapper.selectCategoryById"/>
    
</resultMap>

中可發現還需要映射的屬性有category,因此此時Mybatis會根據column屬性的值,也就是對應Article表中的字段名(外鍵)category_id,拿到之前查出來的 category_id(這裏是7),然後在把id值傳到select屬性對應的語句中:

<select id="selectCategoryById" resultType="site.alanliang.geekblog.domain.Category">
    select id, name from t_category where id = #{id}
</select>

接着發送這條SQL語句,返回結果後映射至category對象中id和name屬性,最後完成所有屬性的映射。

  • 基於SQL表連接

這個比較好理解,直接就是多表連接查詢。需要注意的是,當兩個表中存在字段名一樣的時候,需要給表起別名,我這裏Article和Category的主鍵名字都是id,所以分別起了別名ta和tc,否則沒有辦法映射,Mybatis會報錯。

以上結論均基於個人的理解和總結,如果有不當之處還望指正!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章