1. ResultMap

1.1 基本使用

我们可以使用resultMap标签自定义结果集和实体类属性的映射规则。

  1. <!--
  2. resultMap 用来自定义结果集和实体类的映射
  3. 属性:
  4. id 相当于这个resultMap的唯一标识
  5. type 用来指定映射到哪个实体类
  6. id标签 用来指定主键列的映射规则
  7. 属性:
  8. property 要映射的属性名
  9. column 对应的列名
  10. result标签 用来指定普通列的映射规则
  11. 属性:
  12. property 要映射的属性名
  13. column 对应的列名
  14. -->
  15. <resultMap id="orderMap" type="com.sangeng.pojo.Order" >
  16. <id column="id" property="id"></id>
  17. <result column="createtime" property="createtime"></result>
  18. <result column="price" property="price"></result>
  19. <result column="remark" property="remark"></result>
  20. <result column="user_id" property="userId"></result>
  21. </resultMap>
  22. <!--使用我们自定义的映射规则-->
  23. <select id="findAll" resultMap="orderMap">
  24. SELECT id,createtime,price,remark,user_id FROM ORDERS
  25. </select>

1.2 自动映射

我们定义resultMap时默认情况下自动映射是开启状态的。也就是如果结果集的列名和我们的属性名相同是会自动映射的我们只需要写特殊情况的映射关系即可。
例如:
下面这种写法和上面的写法会有相同的效果,因为其他属性的属性名和结果集的列名都是相同的会自动映射。

<resultMap id="orderMap" type="com.sangeng.pojo.Order" >
        <result column="user_id" property="userId"></result>
    </resultMap>
    <!--使用我们自定义的映射规则-->
    <select id="findAll" resultMap="orderMap">
        SELECT id,createtime,price,remark,user_id  FROM ORDERS
    </select>

如有需要可以选择关闭自动映射可以把resultMap的autoMapping属性设置为false。
例如:

<resultMap id="orderMap" type="com.sangeng.pojo.Order" autoMapping="false">
        <id column="id" property="id"></id>
        <result column="createtime" property="createtime"></result>
        <result column="price" property="price"></result>
        <result column="remark" property="remark"></result>
        <result column="user_id" property="userId"></result>
    </resultMap>

1.3 继承映射关系

我们可以使用resultMap 的extends属性来指定一个resultMap的id,从而复用重复的映射关系配置。
例如:

<!--定义个父映射,供其他resultMap继承-->
    <resultMap id="baseOrderMap" type="com.sangeng.pojo.Order" >
        <id column="id" property="id"></id>
        <result column="createtime" property="createtime"></result>
        <result column="price" property="price"></result>
        <result column="remark" property="remark"></result>
    </resultMap>
    <!--继承baseOrderMap,然后只需要写自己特有的映射关系即可-->
    <resultMap id="orderMap" type="com.sangeng.pojo.Order" autoMapping="false" extends="baseOrderMap">
        <result column="user_id" property="userId"></result>
    </resultMap>

2. 多表查询

有的时候我们需要查询多张表的数据才可以得到我们要的结果。
我们可以直接写一个多表关联的SQL进行查询。也可以分步进行多次的查询来拿到我们需要的结果。
Mybatis就提供了对应的配置,可以让我们去更方便的进行相应的查询和对应的结果集处理。

2.1 多表关联查询

2.1.1 一对一关系

两个实体之间是一对一的关系。(例如我们需要查询订单,要求还需要下单用户的数据。这里的订单相对于用户是一对一。)
例如:
方法定义如下

    //根据订单id查询订单,要求把下单用户的信息也查询出来
    Order findById(Integer id);

因为期望Order中还能包含下单用户的数据,所以可以再Order中增加一个属性

private User user;

SQL语句如下:

SELECT 
o.id,o.`createtime`,o.`price`,o.`remark`,o.`user_id`,u.`id` uid,u.`username`,u.`age`,u.`address`
FROM 
orders o,USER u
WHERE
o.`user_id` = u.`id`
    AND o.id = 2

image-20210224155400455
我们可以使用如下两种方式封装结果集。

2.1.1.1 使用ResultMap对所有字段进行映射

可以使用ResultMap设置user对象的属性的映射规则。

  1. resultMap定义,主要是对user对象的属性设置映射规则 ```xml
2. 使用定义好的resultMapxml <a name="Zl6Ip"></a> ##### 2.1.1.2 使用ResultMap中的association 可以使用ResultMap中的子标签association 来设置关联实体类的映射规则. 1. 定义resultMapxml
<resultMap id="orderMap" type="com.sangeng.pojo.Order" autoMapping="false" extends="baseOrderMap">
    <result column="user_id" property="userId"></result>
</resultMap>

<!--Order和User关联的映射(使用association)-->
<resultMap id="orderUserMapUseAssociation" type="com.sangeng.pojo.Order" autoMapping="false" extends="orderMap">
    <association property="user" javaType="com.sangeng.pojo.User">
        <id property="id" column="uid"></id>
        <result property="username" column="username"></result>
        <result property="age" column="age"></result>
        <result property="address" column="address"></result>
    </association>
</resultMap>

2. 使用resultMap
```sql
<!--根据订单id查询订单,要求把下单用户的信息也查询出来-->
<select id="findById" resultMap="orderUserMapUseAssociation">
SELECT
o.`id`,o.`createtime`,o.`price`,o.`remark`,o.`user_id`,u.`id` uid,u.`username`,u.`age`,u.`address`
FROM
orders o,`user` u
WHERE
o.id = #{id} AND
o.`user_id`=u.`id`
    </select>

2.1.2 一对多关系

两个实体之间是一对多的关系。(例如我们需要查询用户,要求还需要该用户所具有的角色信息。这里的用户相对于角色是一对多的。)
例如:
方法定义如下

//根据id查询用户,并且要求把该用户所具有的角色信息也查询出来
    User findById(Integer id);
//    该用户所具有的角色
    private List<Role> roles;

sql语句如下

SELECT 
    u.`id`,u.`username`,u.`age`,u.`address`,r.id rid,r.name,r.desc
FROM 
    USER u,user_role ur,role r
WHERE 
    u.id=ur.user_id AND ur.role_id = r.id
    AND u.id = 2

2.1.2.1 使用ResultMap中的collection

可以使用ResultMap中的子标签association 来设置关联实体类的映射规则.

  1. 定义ResultMap

    <!--定义User基本属性映射规则-->
     <resultMap id="userMap" type="com.sangeng.pojo.User">
         <id property="id" column="id"></id>
         <result property="username" column="username"></result>
         <result property="age" column="age"></result>
         <result property="address" column="address"></result>
     </resultMap>
    
     <resultMap id="userRoleMap" type="com.sangeng.pojo.User"  extends="userMap">
         <collection property="roles" ofType="com.sangeng.pojo.Role" >
             <id property="id" column="rid"></id>
             <result property="name" column="name"></result>
             <result property="desc" column="desc"></result>
         </collection>
     </resultMap>
    
  2. 使用ResultMap

    <select id="findById" resultMap="userRoleMap" >
         SELECT 
             u.`id`,u.`username`,u.`age`,u.`address`,r.id rid,r.name,r.desc
         FROM 
             USER u,user_role ur,role r
         WHERE 
             u.id=ur.user_id AND ur.role_id = r.id
             AND u.id = #{id}
     </select>
    

    2.2 分步查询

    如果有需要多表查询的需求我们也可以选择用多次查询的方式来查询出我们想要的数据。Mybatis也提供了对应的配置。
    例如我们需要查询用户,要求还需要查询出该用户所具有的角色信息。我们可以选择先查询User表查询用户信息。然后在去查询关联的角色信息。

    2.2.1实现步骤

    具体步骤如下:

  3. 定义查询方法

因为我们要分两步查询: 1.查询User 2.根据用户的id查询Role 所以我们需要定义下面两个方法,并且把对应的标签也先写好
①查询user

//根据用户名查询用户,并且要求把该用户所具有的角色信息也查询出来
    User findByUsername(String username);
<!--根据用户名查询用户-->
<select id="findByUsername" resultType="com.sangeng.pojo.User">
  select id,username,age,address from user where username = #{username}
    </select>

②根据user_id查询Role

public interface RoleDao {
    //根据userId查询所具有的角色
    List<Role> findRoleByUserId(Integer userId);
}
<!--根据userId查询所具有的角色-->
<select id="findRoleByUserId" resultType="com.sangeng.pojo.Role">
  select 
  r.id,r.name,r.desc
  from 
  role r,user_role ur
  where 
  ur.role_id = r.id
  and ur.user_id = #{userId}
    </select>
  1. 配置分步查询

我们期望的效果是调用findByUsername方法查询出来的结果中就包含角色的信息。所以我们可以设置findByUsername方法的RestltMap,指定分步查询

<resultMap id="userMap" type="com.sangeng.pojo.User">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="age" column="age"></result>
        <result property="address" column="address"></result>
    </resultMap>
    <!--
           select属性:指定用哪个查询来查询当前属性的数据 写法:包名.接口名.方法名
           column属性:设置当前结果集中哪列的数据作为select属性指定的查询方法需要参数
       -->
    <resultMap id="userRoleMapBySelect" type="com.sangeng.pojo.User" extends="userMap">
        <collection property="roles"
                    ofType="com.sangeng.pojo.Role"
                    select="com.sangeng.dao.RoleDao.findRoleByUserId"
                    column="id">
        </collection>
    </resultMap>

指定findByUsername使用我们刚刚创建的resultMap

<!--根据用户名查询用户-->
    <select id="findByUsername" resultMap="userRoleMapBySelect">
        select id,username,age,address from user where username = #{username}
    </select>

2.2.2 设置按需加载