使用Mybatis联表查询的几种方式

mybatis的association以及collection的用法

前言:
在项目中,某些实体类之间肯定有关联关系,比如一对一,一对多等。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
 

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值