注意事项

  • 在使用一对多关系时,不要重写toString(),因为User类中有属性Pet,在Pet类中有属性User,会造成两个entity来回调用,造成栈溢出。尤其使用lombok时要注意,它的@Data注解是默认重写了toString()的,出错在个这个不起眼的注解上,难以排错。
  • 正确的使用方式是通过getXX()的方式来获得返回值。

一对多的映射

推荐的XXMapper.xml方式

一个人,可以有多个宠物。这是主人的entity。注意此处属性Pet是用的List<>集合,表示会对应多个。

public class User {
    private Integer user_id;
    private String name;
    //这儿到底该是pet还是List<Pet>?是List,一对多
    private List<Pet> pets;
}

映射语句UserMapper.xml的写法:

<mapper namespace="com.stein.mapper.UserMapper">
    
    <resultMap id="userResultType" type="User">
        <!--1-2句,封装entity的属性值-->
        <id property="user_id" column="user_id"/>
        <result property="name" column="name"/>
        
        <!--column="user_id"这儿是入参。ofType是集合<>括号里面的类型,写不写没看出差异-->
        <!--这是第3句,利用另一句sql查询语句,查询另一张表,由指向的方法来封装子类型的属性值-->
        <collection property="pets" column="user_id" ofType="Pet"
                    select="com.stein.mapper.PetMapper.queryPetById"/>
    </resultMap>
    
    <!--sql语句的主体,返回类型嵌套其他类型,使用了resultMap-->
    <select id="queryUserById" parameterType="Integer" resultMap="userResultType">
        select * from user where user_id=#{userid}
    </select>

@注解方式

@Select("Select * from user where user_id=#{userid}")
    @Results({
            @Result(id = true,property = "user_id",column = "user_id"),
            @Result(property = "name",column = "name"),
            @Result(property="pets",column="user_id",
                    many=@Many(select="com.stein.mapper.PetMapperAnnotation.queryPetById"))
    })
    User queryUserById(Integer userid);

一只宠物,对应一个主人。这是宠物的entity。注意此处属性User只有一个。

public class Pet {
    private Integer pet_id;
    private String name;
    private User user;
}

映射语句PetMapper.xml的写法:
此处宠物与主人一对一,所以用的<association>。但是宠物有多只啊,这儿只写了单个的情况,是如何实现多个呢,个人猜测是在UserMapper的<collection>进行了遍历,在此处执行了多次来实现的。

<mapper namespace="com.stein.mapper.PetMapper">
    <resultMap id="petResultType" type="Pet">
        <id property="pet_id" column="pet_id"/>
        <result property="name" column="pet_name"/>
        <association property="user" column="user_id" select="com.stein.mapper.UserMapper.queryUserById"/>
    </resultMap>
    <select id="queryPetById" parameterType="Integer" resultMap="petResultType">
        select * from pet where user_id=#{userId}
    </select>
</mapper>

@注解方式

为了便于复用,添加了属性id,给该ResultMap取一个名字。此时value不可省略,后面跟的是Result[ ]数组。
@Select("select * from pet where user_id=#{userId}")
    @Results(id="petResultMap",value={
            @Result(id = true,property = "pet_id",column = "pet_id"),
            @Result(property = "name",column = "pet_name"),
            @Result(property="user",column="user_id",
                    one=@One(select="com.stein.mapper.UserMapperAnnotation.queryUserById"))
    })
    List<Pet> queryPetById(Integer userId);

resultMap的复用

  • 现在要在宠物表中,先使用petId查询pet信息表,封装宠物属性;再利用查询得到的主人id,在主人表中,查询主人信息。
  • 而上面PetMapper.xml已经在<resultMap id=“petResultType”> 中,用宠物表中,用主人id查询宠物信息,先封装宠物属性;再在主人表中,用主人id,查询主人信息。
  • 此时resultMap的作用就是封装宠物信息,查询主人信息,所用到的操作完全一模一样。此时便可进行复用。
<select id="queryPetByPetId" parameterType="Integer" resultMap="petResultType">
       select * from pet where pet_id=#{petId}  //不同的sql语句
   </select>

@注解方式

可以使用@ResultMap引用id来复用,也可以直接复制要引用的部分。

@Select("select * from pet where pet_id=#{petId}")
    @ResultMap("petResultMap")
    Pet queryPetByPetId(Integer petId);

使用方法总结:

  • 可以看出,XXMapper.xml的映射方法,在使用<resultMap>时,column都是指的DB表的列,且作为入参,封装entity的属性。
  • 其中的1-2句是建立封装映射;第3句是通过级联查询或者说二次查询进行封装,column同样是作为入参,实际封装的属性名映射,在select指向的方法语句中体现。
  • @注解方式和xml方式基本相同,但是@注解方式是和接口写在一起的,解耦性不如xml方式,所以不是很推荐。
  • one是一对一
  • many是一对多

关于<association>的两种映射方式:

  • 级联查询(详见上一篇一对一关系):使用join或者cross join进行的级联查询,需要的内容都全部已经返回,此时封装子类型的语句:
<association property="idCard" javaType="IdCard">
            <result property="id" column="card_id"/>
            <result property="card_num" column="card_num"/>
        </association>

参考sql语句:SELECT * FROM person JOIN idcard on person.card_Id = idcard.id and person.id=#{id}

  • 分表查询:利用第一次查询的结果,再查另一张表,得到的结果再封装子类型的语句:
<association property="user" column="user_id" select="com.stein.mapper.UserMapper.queryUserById"/>