mybatis联表查询的几种方式,association和collection的用法

mybatis的association以及collection的用法

  • 前言:
  • 一、association 的三种用法:
    • 第一种用法:association中使用select
    • 第二种方法,嵌套 resultMap
    • 第三种方法:嵌套 resultMap 简化版
  • 二、collection的三种用法:
    • 1、第一种方法:用select,跟association 中使用select类似:
    • 第二种方法:嵌套resultMap
    • 3、第三种方法:嵌套resultMap简化版
  • 三、标签属性介绍
  • 四、特别注意:

前言:

在项目中,某些实体类之间肯定有关联关系,比如一对一,一对多等。mybatis 中使用 association 和 collection 。
association:一对一关联(has one)
collection :一对多关联(has many)

注意:
只有做查询时才会涉及到联表,使用其完成联表查询 。两个标签都可以总结为三种方式。

一、association 的三种用法:

先来看看如下代码(set,get方法没有列出)

public class User {
    private Integer userId;
    private String userName;
    private Integer age;
    private Card card;//一个人一张身份证,1对1
}
public class Card {
    private Integer cardId;
    private String cardNum;//身份证号
    private String address;//地址
}
public interface UserMapper {
    /**
     * 通过userId查询user信息
     * @param userId
     * @return
     */
    User queryById(int userId);
}
 <select id="queryById" parameterType="int" resultMap="userMap">
        SELECT u.user_name,u.age,c.card_id,c.card_num,c.address
        FROM tb_user u,tb_card c
        WHERE u.card_id=c.card_id
        AND
        u.user_id=#{userId}
    </select>

以上是实体类,dao层的设计以及在UserMapper.xml中 queryById 方法的 sql 语句的编写,因为不论用 association的哪种方式,sql语句都是一样的写,sql 语句都是一样的写,不同的只是 userMap 的写法,所以这里先给出这段代码。User 和 Card 是一对一的关系,在数据库中,t_user 表通过外键 card_id 关联 t_card 表。下面分别用 association 的三种用法来实现 queryById 方法。

第一种用法:association中使用select

这种方法需要再定义 CardMapper.java如下:

public interface CardMapper {
   Card queryCardById(int cardId);
}

在 CardMapper.xml 中实现该方法:

 <select id="queryCardById" parameterType="int" resultType="com.ck.smm.entity.Card">
        SELECT *
        FROM tb_card
        WHERE card_id=#{cardId}
 </select>

然后再看 UserMapper.xml 是如何引用这个方法的:

<resultMap type="User" id="userMap">
    <result property="userName" column="user_name"/>
    <result property="age" column="age"/>
   <association property="card" column="card_id" 
                select="com.ck.ssm.dao.CardMapper.queryCardById">
   </association>
</resultMap>

在这里直接通过 select 引用 CardMapper 的 queryById 方法。个人感觉这种方法比较麻烦,因为还要在 CardMapper 里定义 queryCardById 方法并且实现再引用才有用,不过这种方法思路清晰,易于理解。

第二种方法,嵌套 resultMap

<resultMap type="com.ck.smm.entity.Card" id="cardMap">
      <id property="cardId" column="card_id"/>
      <result property="cardNum"  column="card_num"/>
      <result property="address" column="address"/>
</resultMap>

<resultMap type="User" id="userMap">
     <result property="userName" column="user_name"/>
     <result property="age" column="age"/>
     <association property="card" resultMap="cardMap">
     </association>
</resultMap>

第二种方法就是在 UserMapper.xml 中先定义一个 Card 的 resultMap,然后在 User 的r esultMap 的 association 标签中通过 resultMap=“cardMap” 引用。这种方法相比于第一种方法较为简单。

第三种方法:嵌套 resultMap 简化版

<resultMap type="com.ck.smm.entity.User" id="userMap">
   <result property="userName" column="user_name"/>
   <result property="age" column="age"/>
   <association property="card" column="card_id" javaType="com.ck.smm.entity.Card">
      <id property="cardId" column="card_id"/>
      <result property="cardNum" column="card_num"/>
      <result property="address" column="address"/>
    </association>
</resultMap> 

这种方法就把 Card 的 resultMap 定义在了 association 标签里面,通过 javaType 来指定是哪个类的 resultMap,个人认为这种方法最简单,缺点就是 cardMap 不能复用。具体用哪种方法,视情况而定。

二、collection的三种用法:

一个土豪有多个手机,看如下代码:
User实体类

public class User{
    private Integer userId;
    private String userName;
    private Integer age;
    private List<MobilePhone> mobilePhone;//土豪,多个手机,1对多
}

手机类

public class MobilePhone {
    private Integer mobilePhoneId;
    private String brand;//品牌
    private double price;//价格
    private User user;//主人
}

dao层

public interface UserMapper {
    /**
     * 通过userId查询user信息
     * @param userId
     * @return
     */
    User queryById(int userId);
}

UserMapper.xml 中的 select 查询语句

<select id="queryById" parameterType="int" resultMap="userMap">
        SELECT u.user_name,u.age,m.brand,m.price
        FROM tb_user u,tb_mobile_phone m
        WHERE m.user_id=u.user_id
        AND
        u.user_id=#{userId}
</select>

数据库中,tb_mobile_phone 中 user_id 作为外键。那么下面来看 resultMap 如何定义:

1、第一种方法:用select,跟association 中使用select类似:

先定义 MobilePhoneMapper.java

public interface MobilePhoneMapper{
    List<MobilePhone> queryMbByUserId(int userId);
}

然后实现该方法 MobilePhoneMapper.xml

<resultMap type="com.ck.smm.entity.MobilePhone" id="mobilePhoneMap">
     <id property="mobilePhoneId" column="user_id"/>
     <result property="brand" column="brand"/>
     <result property="price" column="price"/>
     <association property="user" column="user_id" 
    			  select="com.ck.ssm.dao.UserMapper.queryById">
     </association>
</resultMap>
<select id="queryMbByUserId" parameterType="int" resultMap="mobilePhoneMap">
        SELECT brand,price
        FROM tb_mobile_phone
        WHERE user_id=#{userId}
    </select>

做好以上准备工作,那就可以在 UserMapper.xml 中引用了

<resultMap type="com.ck.smm.entity.User" id="userMap">
     <id property="userId" column="user_id"/>
     <result property="userName" column="user_name"/>
     <result property="age" column="age"/>
     <collection property="mobilePhone" column="user_id" 
                select="com.ck.ssm.dao.MobilePhoneMapper.queryMbByUserId">
     </collection>
</resultMap> 

这种方法和 association 的 第一种用法几乎是一样的不同之处就是 mobilePhMap 中用到了association ,queryMbByUserId 中要使用mobilePhoneMap,而不能直接使用 resultType。

第二种方法:嵌套resultMap

<resultMap type="com.ck.smm.entity.MobilePhone" id="mobilephoneMap">
      <id column="mobile_phone_id" property="mobilePhoneId"/>
      <result column="brand" property="brand" />
      <result column="price" property="price" />
</resultMap>
<resultMap type="com.ck.smm.entity.User" id="userMap">
     <result property="userName" column="user_name"/>
     <result property="age" column="age"/>
     <collection property="mobilePhone" resultMap="mobilephoneMap" >
     </collection>
</resultMap> 

定义好这两个 resultMap ,再引用 UserMap 就行了。

3、第三种方法:嵌套resultMap简化版

<resultMap type="com.ck.smm.entity.User" id="userMap">
     <result property="userName" column="user_name"/>
     <result property="age" column="age"/>
     <collection property="mobilePhone"column="user_id" ofType="com.ck.smm.entity.MobilePhone">
         <id column="mobile_phone_id" property="mobilePhoneId" />
         <result column="brand" property="brand" />
         <result column="price" property="price" />
     </collection>
</resultMap>

这种方法需要注意,一定要有 ofType,collection 装的元素类型是啥 ofType 的值就是啥,这个一定不能少。

三、标签属性介绍

  • id:命名空间中的唯一标识符,可以被用来引用这条语句

  • parameterType:表示查询语句传入参数的类型的完全限定名或别名,支持基础数 据类型和复杂数据类型。

  • resultType:查询语句返回结果类型的完全限定名或别名。

  • property : 对象属性的名称

  • javaType :对象属性的类型

  • column :所对应的外键字段名称

  • select :使用另一个查询封装的结果

  • ofType :collection中的属性, 用于指定集合中元素的对象类型。

四、特别注意:

表中主键字段要有所区分,不能都写成id,要写成 user_id、card_id,反正要有所区分,不然查询的时候会查不到完整的数据。

参考:https://www.jianshu.com/p/018c0f083501

你可能感兴趣的:(知识点,java)