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会报错。

以上结论均基于个人的理解和总结,如果有不当之处还望指正!

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