分享

mybatis的association和collection的用法

 贪挽懒月 2022-06-20 发布于广东

前言:

在项目中,某些实体类之间肯定有关键关系,比如一对一,一对多等。在hibernate 中用 one to one和 one to many,而mybatis 中就用 association和 collection。 association: 一对一关联(has one)collection:一对多关联(has many) 注意,只有在做select查询时才会用到这两个标签,都有三种用法,且用法类似。

一、association的三种用法:

先看如下代码(省略set、get方法):

  1. public class User {

  2.    private Integer userId;

  3.    private String userName;

  4.    private Integer age;

  5.    private Card card;//一个人一张身份证,1对1

  6. }

  1. public class Card {

  2.    private Integer cardId;

  3.    private String cardNum;//身份证号

  4.    private String address;//地址

  5. }

  1. public interface UserDao {

  2.    /**

  3.     * 通过userId查询user信息

  4.     * @param userId

  5.     * @return

  6.     */

  7.    User queryById(int userId);

  8. }

  1.  <select id="queryById" parameterType="int" resultMap="userMap">

  2.         SELECT u.user_name,u.age,c.card_id,c.card_num,c.address

  3.         FROM tb_user u,tb_card c

  4.         WHERE u.card_id=c.card_id

  5.         AND

  6.         u.user_id=#{userId}

  7.     </select>

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

1、第一种用法:association中使用select

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

  1. public interface CardDao {

  2.    Card queryCardById(int cardId);

  3. }

在CardDao.xml中实现该方法:

  1.  <select id="queryCardById" parameterType="int" resultType="Card">

  2.         SELECT *

  3.         FROM tb_card

  4.         WHERE card_id=#{cardId}

  5.  </select>

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

  1. <resultMap type="User" id="userMap">

  2.    <result property="userName" 

  3.         column="user_name"/>

  4.    <result property="age" 

  5.         column="age"/>

  6.   <association property="card" 

  7.         column="card_id" 

  8.         select="com.zhu.ssm.dao.

  9.         CardDao.queryCardById">

  10.   </association>

  11. </resultMap>

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

2、第二种方法,嵌套resultMap

  1. <resultMap type="Card" id="cardMap">

  2.      <id property="cardId" 

  3.            column="card_id"/>

  4.      <result property="cardNum" 

  5.                   column="card_num"/>

  6.      <result property="address" 

  7.                   column="address"/>

  8. </resultMap>

  9. <resultMap type="User" id="userMap">

  10.     <result property="userName" 

  11.                  column="user_name"/>

  12.     <result property="age" 

  13.                  column="age"/>

  14.     <association property="card" 

  15.                             resultMap="cardMap">

  16.     </association>

  17. </resultMap>

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

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

  1. <resultMap type="User" id="userMap">

  2.   <result property="userName" 

  3.                  column="user_name"/>

  4.   <result property="age" 

  5.                  column="age"/>

  6.   <association 

  7.          property="card"

  8.           column="card_id" 

  9.          javaType="Card">

  10.      <id property="cardId" 

  11.                column="card_id"/>

  12.      <result property="cardNum"

  13.                       column="card_num"/>

  14.      <result property="address" 

  15.                       column="address"/>

  16.    </association>

  17. </resultMap> 

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

二、collection的三种用法:

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

  1. public class User{

  2.  private Integer userId;

  3.    private String userName;

  4.    private Integer age;

  5.    private List<MobilePhone> mobilePhone;//土豪,多个手机,1对多

  6. }

手机类

  1. public class MobilePhone {

  2.    private Integer mobilePhoneId;

  3.    private String brand;//品牌

  4.    private double price;//价格

  5.    private User user;//主人

  6. }

dao层

  1. public interface UserDao {

  2.    /**

  3.     * 通过userId查询user信息

  4.     * @param userId

  5.     * @return

  6.     */

  7.    User queryById(int userId);

  8. }

UserDao.xml中的select查询语句:

  1. <select id="queryById" parameterType="int" resultMap="userMap">

  2.         SELECT u.user_name,u.age,

  3.                       m.brand,m.price

  4.         FROM tb_user u,tb_mobile_phone m

  5.         WHERE m.user_id=u.user_id

  6.         AND

  7.         u.user_id=#{userId}

  8. </select>

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

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

先定义 MobilePhoneDao.java

  1. public interface MobilePhoneDao {

  2.    List<MobilePhone> queryMbByUserId(int userId);

  3. }

然后实现该方法 MobilePhoneDao.xml

  1. <resultMap type="MobilePhone"

  2.                    id="mobilePhoneMap">

  3.     <id property="mobilePhoneId" 

  4.           column="user_id"/>

  5.     <result property="brand" 

  6.                  column="brand"/>

  7.     <result property="price" 

  8.                  column="price"/>

  9.     <association property="user" 

  10.               column="user_id" select=

  11.      "com.zhu.ssm.dao.UserDao.queryById">

  12.     </association>

  13. </resultMap>

  1. <select id="queryMbByUserId" parameterType="int" resultMap="mobilePhoneMap">

  2.         SELECT brand,price

  3.         FROM tb_mobile_phone

  4.         WHERE user_id=#{userId}

  5.     </select>

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

  1. <resultMap type="User" id="userMap">

  2.         <id property="userId" column="user_id"/>

  3.         <result property="userName" 

  4.                     column="user_name"/>

  5.    <result property="age" 

  6.                     column="age"/>

  7.    <collection property="mobilePhone" 

  8.                column="user_id" 

  9.                select="com.zhu.ssm.dao

  10.       .MobilePhoneDao.queryMbByUserId">

  11.        </collection>

  12. </resultMap> 

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

2、第二种方法:嵌套resultMap

  1. <resultMap type="MobilePhone" id="mobilephoneMap">

  2.          <id column="mobile_phone_id" property="mobilePhoneId"/>

  3.          <result column="brand" property="brand" />

  4.         <result column="price" property="price" /></resultMap>

  1.     <resultMap type="User" id="userMap">

  2.         <result property="userName" column="user_name"/>

  3.        <result property="age" column="age"/>

  4.        <collection property="mobilePhone" resultMap="mobilephoneMap" >

  5.        </collection>

  6. </resultMap> 

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

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

  1. <resultMap type="User" id="userMap">

  2.         <result property="userName" column="user_name"/>

  3.     <result property="age" column="age"/>

  4.     <collection property="mobilePhone"

  5.                  column="user_id" 

  6.                 ofType="MobilePhone">

  7.      <id column="mobile_phone_id" property="mobilePhoneId" />

  8.      <result column="brand" 

  9.                       property="brand" />

  10.      <result column="price"

  11.                       property="price" />

  12.  </collection>

  13. </resultMap>

这种方法需要注意,一定要有ofType,collection 装的元素类型是啥ofType的值就是啥,这个一定不能少。注意: 所有resultMap中的type、select 标签中的resultType以及association中的javaType,collection中的ofType,这里只写了类名,是因为在mybatis-config.xml中配置了typeAliases,否则就要写该类的全类名。配置如下:

  1. <typeAliases>

  2. <packagename="com.zhu.smm.entity"/>

  3. </typeAliases>

总结:

1、association表示的是has one的关系,一对一时使用。user has one card,所以在user的resultMap中接收card时应该用association; 

2、collection表示的是has many的关系,一对多时使用。user has many mobilePhone,所以在user的resultMap中接收mobilePhone时应该用collection 。

3、都有三种用法,且非常类似,resultMap要复用建议第二种方法,不需要复用建议第三种方法。 

4、特别注意表中主键字段要有所区分,不能都写成id,要写成userid、cardid,反正要有所区分,不然查询的时候会查不到完整的数据。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约