Mybatis一对一映射

1.前言

MyBatis是一款优秀的支持自定义SQL查询,存储过程和高级映射的持久层框架,消除了几乎所有的JDBC代码和参数的手动设置以及结果集的检索。MyBatis可以使用XML或注解进行配置和映射,MyBatis通过将参数映射到配置的SQL形成最终执行的SQL语句,最后将执行SQL的结果映射成Java对象返回。这篇文章主要介绍Mybatis框架提供的一对一映射功能。

2.一对一映射

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

MyBatis可以通过别名将值匹配到对应的字段,简单的别名映射包括SQL语句的user_name字段映射到Java对象的userName属性。除此之外,MyBatis还支持复杂的嵌套映射,可以多层嵌套。例如SQL语句的“role.role_name”字段的映射过程:  MyBatis会先查找Java对象的role属性,如果存在role属性就创建role对象。然后在role对象中继续查找roleName属性,将role_name的值绑定到role对象的roleName属性上。

/**
* 用户表
*/
public class SysUser {

     //其他原有字段

     /**
     *   用户角色
     */
     private SysRole role;

 
     //其他原有的setter和getter字段


     public SysRole getRole(){
         return role;
     }

     public void setRole(SysRole role){
         this.role=role;
     }

}

xml文件对应的select内容为:

<select id="selectUserAndRoleById" resultType="SysUser">
   select u.id, u.user_name userName, u.user_password userPassword,
          u.user_email userEmail,
          r.id "role.id", r.role_name "role.roleName", r.enabled "role.enabled",
          r.create_by "role.createBy", r.create_time "role.createTime"
          from sys_user u
          inner join sys_user_role ur on u.id = ur.user_id
          inner join sys_role r on ur.role_id = r.id
          where u.id = #{id}
</select>

2.2 使用resultMap配置一对一映射

除了使用MyBatis的自动映射来处理一对一嵌套外,还可以在XML映射文件中配置结果映射。使用resultMap可以实现与上一节的例子相同的效果。

在XML文件增加如下的resultMap配置:

<resultMap id="userRoleMap" type="SysUser">
    <id property="id" column="id"/>
    <result property="userName" column="user_name"/>
    <result property="userPassword" column="user_password>
    <result property="userEmail" column="user_email"/>
    <result property="userInfo" column="user_info"/>
    <result property="headImg" column="head_img" jdbcType="BLOB"/>
    <!--role相关属性-->
    <result property="role.id" column="role_id"/>
    <result property="role.roleName" column="role_name"/>
    <result property="role.enabled" column="enabled"/>
    <result property="role.createBy" column="create_by"/>
    <result property="role.createTime" column="role_create_time" jdbcType="TIMESTAMP"/> 
</resultMap>

2.3 使用resultMap的association标签配置一对一映射

在resultMap中, association标签用于和一个复杂的类型进行关联,即用于一对一的关联配置。

在上面resultMap配置的基础上,修改成association标签的配置方式,代码如下:

<resultMap id="userRoleMap" type="SysUser">
    <id property="id" column="id"/>
    <result property="userName" column="user_name"/>
    <result property="userPassword" column="user_password>
    <result property="userEmail" column="user_email"/>
    <result property="userInfo" column="user_info"/>
    <result property="headImg" column="head_img" jdbcType="BLOB"/>
    <association property="role" columnPrefix="role_" javaType="SysRole">
      <result property="id" column="id"/>
      <result property="roleName" column="role_name"/>
      <result property="enabled" column="enabled"/>
      <result property="createBy" column="create_by"/>
      <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/> 
    </association>
</resultMap>

对于修改后的resultMap,因为配置了列的前缀,因此还需要修改SQL,代码如下:

<select id="selectUserAndRoleById2" resultType="SysUser">
   select u.id, u.user_name userName, u.user_password userPassword,
          u.user_email userEmail,
          r.id "role_id", r.role_name "role_role_name", r.enabled "role_enabled",
          r.create_by "role_create_by", r.create_time "role_create_time"
          from sys_user u
          inner join sys_user_role ur on u.id = ur.user_id
          inner join sys_role r on ur.role_id = r.id
          where u.id = #{id}
</select>

注意和sys_role相关列的别名,都已经改成了"role_"前缀,特别注意role_name增加前缀后为role_role_name。

目前已经讲到的3种情况都属于“关联的嵌套结果映射”,即通过一次SQL查询根据表或指定的属性映射到不同的对象中。

2.4  association标签的嵌套查询

除了前面3种通过复杂的SQL查询获取结果,还可以多次利用简单的SQL查询转换为需要的结果。这种方式与根据业务逻辑手动执行多次SQL的方式类似,最后会将结果组合成一个对象。

association标签的嵌套查询常用的属性如下:

  • select:  另一个映射查询的id,MyBatis会额外执行这个查询获取嵌套对象的结果
  • column:  列名(或别名),将主查询列的结果作为嵌套查询的参数,配置方式如column={prop1=col1,prop2=col2},prop1和prop2将作为嵌套查询的参数
  • fetchType:  数据加载方式,可选值为lazy和eager,分别为延迟加载和积极加载,这个配置会覆盖全局的lazyLoadingEnabled配置。

association标签的type和select属性分别代表一次性查询和多次查询。

可以使用嵌套查询的方式配置一个和前面功能一样的方法,首先在XML文件中创建如下的resultMap:

<resultMap id="userRoleMapSelect" extends="userMap" type="SysUser">
    <association property="role" column="{id=role_id}" 
     select="selectRoleById"/>
</resultMap>

然后创建两个select方法,代码如下:

<select id="selectUserAndRoleByIdSelect" resultMap="userRoleMapSelect">
    select u.id, u.user_name, u.user_password, u.user_email,u.user_info,
           u.head_img, u.create_time, ur.role_id
    from sys_user u
    inner join sys_user_role ur on u.id = ur.user_id
    where u.id=#{id}
</select>

<select id="selectRoleById" resultMap="roleMap">
    select * from sys_role where id = #{id}
</select>

注意:可用的参数是通过上面的column="{id=role_id}"进行配置的,因此在嵌套的SQL中只能使用#{id}参数,当需要多个参数时,可以配置多个,使用逗号隔开即可。例如column="{id=role_id,name=role_name}"。

这种方式符合开始时预期的结果。但是由于嵌套查询会多次执行SQL,所以还要考虑效率。如果业务代码没有用到返回结果的role属性的话,那么多出来的selectRoleById查询就没有意义。那么如何解决这个问题呢?

在上面介绍association标签的属性时,介绍了fetchType的数据加载方式,这种方式可以帮助我们实现延迟加载。按照上面的介绍,需要把fetchType设置为lazy。这样设置后,只有当调用getRole()方法获取role的时候,MyBatis才会执行嵌套查询去获取数据。

在MyBatis的全局配置中,有一个参数为aggressiveLazyLoading,默认为true。当该参数为true的时候,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载,反之,每种属性都将按需加载。

需要将aggressiveLazyLoading设置为false,才能保证延迟加载正常工作:

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

有些时候,还是会存在希望触发某些方法的时候将所有的数据加载进来的情况。MyBatis提供了lazyLoadTriggerMethods参数帮助解决这个问题。lazyLoadTriggerMethods参数的含义:当调用配置中的方法时,加载全部的延迟加载数据。默认值为"equals,clone,hashcode,toString"。

2.5 各个映射方式的比较

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值