MyBatis 一对一映射

Posted junjie2019

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis 一对一映射相关的知识,希望对你有一定的参考价值。

From《MyBatis从入门到精通》

 

 

    <!--
        6.1 高级映射结果

        杂谈:
            在RBAC权限系统中还存在着一个用户拥有多个角色,一个角色拥有多个权限这样
            复杂的嵌套关系。在面对这种关系时,我们可以写出多个方法分别查询这些数据,
            然后在组合在一起。这种处理方式特别适合用在大型系统上,由于分库分表,这种
            这种用法可以减少表之间的关联查询,方便系统进行扩展。但是在一般的企业级应用
            中,使用MyBatis的高级结果映射便可以轻松地处理这种一对一、一对多的关系。
    -->

    <!--
        6.1.1 一对一映射
            6.1.1.1 使用自动映射处理一对一关系
                关联的嵌套结果映射需要关联多个表,将所有需要的值一次性查询出来。这种方式的好处是
                减少数据库查询次数,减轻数据库的压力,缺点是要写很复杂的SQL,并且当嵌套结果更复杂
                时,不容易一次写正确,由于要在应用服务器上将结果映射到不同的类上,因此也会增加应用
                服务器的压力。当一定会使用嵌套结果,并且这个复杂的SQL执行速度很快时,建议使用
                关联的嵌套结果映射。

            6.1.1.2 使用resultMap配置一对一映射
                resultMap配置一对一映射时有两种方法:
                    1.很传统的在resultMap中一一的指定列名对应的属性名
                    2.通过extends一个userMap,加上一些字段来实现。
                        ——我对这个东西始终有些疑惑,你直接去修改JavaBean
                        真的是一种可以接受的方案么,你这样做了,以后代码自动
                        生成时怎么弄呢???

            6.1.1.3 使用resultMap的association标签配置一对一映射
                在resultMap中,association标签用于和一个复杂的类型进行关联,
                即用于一对一的关联配置。
                
                <association>标签包含的属性:
                    property:对应实体类中的属性名,必填项
                    javaType:属性对应的Java类型
                    resultMap:可以直接使用现有的resultMap,而不在这里配置
                    columnPrefix:查询列的前缀、配置前缀后、在子标签配置result的column时可以省略前缀
    -->
    <resultMap id="userRoleMap" extends="userMap" type="tk.mybatis.simple.mode.SysUser">
        <association property="role" columnPrefix="_role"
                     javaType="tk.mybatis.simple.model.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"/>
        </association>
    </resultMap>
    
    <!--进一步升级后的代码-->
    <!--
        
    -->
    <resultMap id="userRoleMap" extends="userMap" type="tk.mybatis.simple.model.SysUser">
        <association property="role" columnPrefix="role_" resultMap="roleMap"/>
    </resultMap>
    
    <!--
        6.1.1.4 association标签的嵌套查询
            除了前面3种通过复杂的SQL查询获取结果,还可以利用简单的SQL通过多次查询
            转换为我们需要的结果。这种方式与根据业务逻辑手动执行多次SQL的方式很像,
            最后会将结果组合成一个对象。
                
            <association>标签的嵌套查询常用的属性如下:
                select:另一个映射查询的id,Mybatis会额外执行这个查询获取对象的结果
                column:列名(或别名),将主查询中列的结果作为嵌套查询的参数,配置方式
                    如下:column={prop1=col1,prop2=col2},prop1和prop2将作为嵌套
                    查询的参数。
                fetchType:数据加载方式,可选值为lazy和eager,分别为延迟加载和积极加载
                    这个配置会覆盖全局的lazyLoadingEnabled配置
    -->
    <resultMap id="userRoleMapSelect" extends="userMap"
               type="tk.mybatis.simple.model.SysUser">
        <association property="role" column="{id=role_id}"
                     select="tk.mybatis.simple.mapper.RoleMapper.selectRoleById"/>
    </resultMap>
    
    <!--
        案例分析:
            这个看上去就像在普普通通的在sys_user表和sys_user_role表
            的连接上查找一个SysUser对象的。但是这个SysUser对象里有一个Role对象。
                ——我不知道这种方案与我手写两次查询有什么区别,而且我还
                感觉我手写两次,用的脑子更少一点。
                
                ——现在我都开始在怀疑在User中添加Role字段的意义了,只是
                为了在一个返回中涉及两个表的内容么???
    -->
    <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>
    
    <!--
        杂话:
            1.单纯设置<association>标签的fetchType属性为true时,并不会实现延迟加载
            功能。这是因为在MyBatis的全局配置中,有一个参数为aggressiveLazyLoading
            这个参数的含义是,当该参数这是为true时,对任意延迟属性的调用都会是带有延迟加
            载属性的对象完整加载,反之,每种属性都将按需加载。
            
            2.集成框架是,可能由于SqlSession的生命周期交给了框架管理,导致对象超出了SqlSession
            生命周期调用时,会由于连接关闭等问题而抛出异常。在和Spring集成时,要确保
            只能在Service层调用延迟加载的属性。当结果从Service层返回到Controller层时,
            如果获取延迟加载的属性值,会因为SqlSession已经关闭而抛出异常。
            
            3.由于关闭了aggressiveLazyLoading,但有时我们还是需要在触发某个方式时将
            所有的数据都加载进来。MyBatis提供了参数lazyLoadTriggerMethods帮助解决
            这个问题。这个参数的含义是,当调用配置中的方法时,加载全部的延迟加载数据,默
            认值为"equals clone hashCode toString"。因此,在使用默认的情况下,只要
            调用其中一个方法,就可以实现加载调用对象的全部数据。
    -->

 

以上是关于MyBatis 一对一映射的主要内容,如果未能解决你的问题,请参考以下文章

mybatis第二天——大纲待更新

mybatis映射 一对一,一对多,多对多高级映射

mybatis映射 一对一一对多多对多高级映射

Mybatis一对一,一对多,多对多代码

Mybatis学习总结——高级映射(一对一,一对多,多对多)

Mybatis框架中实现一对多关系映射