Mybatis-高级映射

179 阅读3分钟
  1. 一对一映射:

    • 使用自动映射处理一对一关系:

      public class User {
          private Integer id;
          private String username;
          private String userEmail;
          /**
           * 角色
           */
          private Role role;
          
          // 省略其它代码
      }
      
      public class Role {
          private Integer id;
          private String roleName;
          // 省略其它代码
      }
      
      <select id="selectUserAndRoleById" resultType="study.User">
          SELECT 
                 id,
                 username,
                 userEmail,
                 <!--注意这里的别名-->
                 role.id AS "role.id",
                 <!--注意这里的别名-->
                 role.role_name AS "role.roleName"
            FROM user 
                 INNER JOIN user_role 
                         ON user_role.role_id = user.id
                 INNER JOIN role
                         ON role.id = user_role.role_id
            WHERE user.id = #{id}
      </select>
      
    • 使用 resultMap 配置一对一映射:

      • 一般写法:

        <resultMap id="uesrRoleMap" type="study.User">
            <id property="id" column="id"/>
            <result property="username" column="username"/>
            <result property="userEmail" column="user_email"/>
            <result property="role.id" column="role_id"/>
            <result property="role.roleName" column="role_name"/>
        </resultMap>
        
        <select id="selectUserAndRoleById" resultMap="uesrRoleMap">
            SELECT 
                   id,
                   username,
                   userEmail,
                   <!--注意这里的别名-->
                   role.id AS role_id,
                   <!--注意这里的别名-->
                   role.role_name
              FROM user 
                   INNER JOIN user_role 
                           ON user_role.role_id = user.id
                   INNER JOIN role
                           ON role.id = user_role.role_id
              WHERE user.id = #{id}
        </select>
        

        注意这里在 resultMap 中配置的 column 名称要和 SQL 语句查询结果的别名相同.

      • 使用继承的方式:

        <!--User 的 resultMap-->
        <resultMap id="userMap" type="study.User">
            <!--这些是可以被继承的-->
            <id property="id" column="id"/>
            <result property="username" column="username"/>
            <result property="userEmail" column="user_email"/>
        </resultMap>
        
        <!--带 Role 的 User 的 resultMap-->
        <resultMap id="uesrRoleMap" extends="userMap" type="study.User">
            <result property="role.id" column="role_id"/>
            <result property="role.roleName" column="role_name"/>
        </resultMap>
        

        这里继承的只是 userMap 中的 id 和 result 子元素.

      • 使用 Association 方式:

        <resultMap id="uesrRoleMap" extends="userMap" type="study.User">
            <association property="role" columnPrefix="role_" javaType="study.Role">
                <result property="id" column="id"/>
                <result property="roleName" column="role_name"/>
            </association>
        </resultMap>
        
        <select id="selectUserAndRoleById" resultMap="uesrRoleMap">
            SELECT 
                   id,
                   username,
                   userEmail,
                   <!--注意这里的别名, 所有列名必须要有 role_ 前缀-->
                   role.id AS role_id,
                   <!--注意这里的别名, 所有列名必须要有 role_ 前缀-->
                   role.role_name AS role_role_name
              FROM user 
                   INNER JOIN user_role 
                           ON user_role.role_id = user.id
                   INNER JOIN role
                           ON role.id = user_role.role_id
              WHERE user.id = #{id}
        </select>
        
    • association 标签的嵌套查询:

      <resultMap id="uesrRoleMap" extends="userMap" type="study.User">
          <association property="role" javaType="study.Role" column="{id=role_ID}"
          select="study.mapper.RoleMapper.selectRoleById"/>
      </resultMap>
      
      <select id="selectUserAndRoleByIdSelect" resultMap="uesrRoleMap">
          SELECT 
                 id,
                 username,
                 userEmail,
                 user_role.role_id
            <!--注意这里并没有从 role 表中查询信息了-->
            FROM user 
                 INNER JOIN user_role 
                         ON user_role.role_id = user.id
            WHERE user.id = #{id}
      </select>
      
      <select id="selectRoleById" resultMap="roleMap">
          SELECT id,
                 role_name
            FROM role
           WHERE id = #{id} 
      </select>
      

      这里还可以将 fetchType 设置为 lazy. 这样设置之后, 只有当调用 User#getRole() 方法才会执行嵌套查询去获取数据. 这时需要将在 mybatis-config.xml 中增加:

      <settings>
          <setting name="aggressiveLazyLoading" value="false"/>
      </settings>
      

      Mybatis 还提供了 lazyLoadTriggerMethods 来定义某些方法, 当调用这些方法时, 会加载全部的延迟加载数据.

  2. 一对多映射:

    • collection 集合的嵌套结果映射:

      public class User {
          private Integer id;
          private String username;
          private String userEmail;
          /**
           * 角色
           */
          private List<Role> roles;
          
          // 省略其它代码
      }
      
      <resultMap id="uesrRoleMap" extends="userMap" type="study.User">
          <collection property="roles" columnPrefix="role_" javaType="study.Role"
          <!--这里引用 roleMap -->
          resultMap="study.mapper.RoleMapper.roleMap"/>
      </resultMap>
      
      <select id="selectAllUserAndRoles" resultMap="uesrRoleMap">
          SELECT 
                 id,
                 username,
                 userEmail,
                 <!--注意这里的别名, 所有列名必须要有 role_ 前缀-->
                 role.id AS role_id,
                 <!--注意这里的别名, 所有列名必须要有 role_ 前缀-->
                 role.role_name AS role_role_name
            FROM user 
                 INNER JOIN user_role 
                         ON user_role.role_id = user.id
                 INNER JOIN role
                         ON role.id = user_role.role_id
      </select>
      

      Mybatis 在处理结果的时候, 会判断结果是否相同. 如果是相同的结果, 则只会保留第一个结果. MyBatis 判断结果是否相同时, 最简单的是根据 resultMap 中映射配置的 id 标签. 在 userMap 中配置如下:

      <id property="id" column="id"/>
      

      id 的唯一作用就是在嵌套的映射配置时判断数据相同.

  3. 鉴别器映射:

     ```
     <resultMap id="userRoleMapChoose" resultType="study.User">
         <discriminator column="enabled" javaType="int">
             <case value="1" resultMap="uesrRoleMap"/>
             <case value="0" resultMap="userMap"/>
         </discriminator>
     </resultMap>
     
     <select id="selectUserAndRoleById" resultMap="userRoleMapChoose">
         SELECT 
                id,
                username,
                userEmail,
                <!--注意这里的别名-->
                role.id AS "role.id",
                <!--注意这里的别名-->
                role.role_name AS "role.roleName"
           FROM user 
                INNER JOIN user_role 
                        ON user_role.role_id = user.id
                INNER JOIN role
                        ON role.id = user_role.role_id
           WHERE user.id = #{id}
     </select>
     ```
    

    当用户的 enabled 值为 1 的时候表示用户被启用, 0 的时候表示用户不可用. 当用户可用时, 使用 userRoleMap 映射, 可以获取到用户信息和角色信息; 当用户不可以用时, 使用 userMap 只能获取到用户信息.

  4. 参考:
    [1] : MyBatis从入门到精通