7、ORM映射

本文详细介绍了MyBatis中的ORM映射,包括如何处理属性与字段命名不一致的情况,通过别名、全局设置和resultMap实现映射。此外,还探讨了多对一和一对多映射的解决方案,如级联映射、association标签和分步查询,并提到了延迟加载的开启方式。
摘要由CSDN通过智能技术生成

7、ORM映射

ORM(Object Relational Mapping)对象关系映射,解决面向对象与关系数据库存在的互不匹配的现象的技术,将程序中的对象自动持久化到关系数据库中。

在这里插入图片描述

可以看到,实体类中的属性和数据库中的字段根据命名一一对应。

7.1、解决属性与字段名不一致

上面我们了解到,属性和字段根据相同的命名一一映射,假设名字不一致呢?

比如现有一个学生表s_student和学生实体类:

在这里插入图片描述

在这里插入图片描述

可以看到,属性和字段名并不一样,属性是按照java命名规范的驼峰命名,字段是按照sql规范的下划线命名。

这种情况有三种解决方法:

1、通过字段别名来解决

可以利用sql语句为字段取与属性名相同的别名,来与属性名对应。

<select id="selectAllStudent" resultType="Student">
    select s_id sId,s_name sName,s_age sAge,s_sex sSex,s_email sEmail,s_class sClass 
    from t_student
</select>

2、通过配置全局设置mapUnderscoreToCamelCase(有前提条件)

mapUnderscoreToCamelCase全局设置是用来解决java的驼峰命名与sql的下划线命名规范的。所以要使用这个方法前提是,数据库字段命名必须用规范的下划线命名同时实体类的属性命名必须按照驼峰规范命名。

<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

在满足前提条件的情况下,在核心配置中加入如上配置即可。

3、通过resultMap自定义映射

在接口对应的映射文件中自定义resultMap来解决:

<resultMap id="studentresultMap" type="Student">
    <id property="sId" column="s_id"></id>
    <result  property="sName"  column="s_name"></result>
    <result  property="sAge"  column="s_age"></result>
    <result  property="sSex"  column="s_sex"></result>
    <result  property="sEmail"  column="s_email"></result>
    <result  property="sClass"  column="s_class"></result>
</resultMap>
<select id="selectAllStudent" resultMap="studentresultMap">
    select * from t_student
</select>

如上:id标签代表主键;property代表实体类的属性名,column代表数据库中的字段名。

自定义映射后,在相应的sql语句中引入 resultMap=""即可。

7.2、解决多对一的映射

现有两张表:

学生表:t_student

在这里插入图片描述

班级表:t_class

在这里插入图片描述

在学生表中,设置一个逻辑外键s_class存放班级id就可以通过联表查询获取到班级信息。

那么在学生实体类中,要想存放班级信息属于多对一的映射。班级信息----------->学生的一个属性。

可以在学生实体类中设置一个班级实体类作为一个属性,用来存放班级信息。

在这里插入图片描述

具体映射有三种方法:

1、级联映射

对应的映射文件:

<resultMap id="selectAllStudentAndClassMap" type="Student">
    <id property="sId" column="s_id"></id>
    <result property="sName" column="s_name"></result>
    <result property="sAge" column="s_age"></result>
    <result property="sSex" column="s_sex"></result>
    <result property="sEmail" column="s_email"></result>
    <result property="sClass.cId" column="c_id"></result>
    <result property="sClass.cName" column="c_name"></result>
</resultMap>
<!--    List<Student> selectAllStudentAndClass(@Param("sId") Integer sId);-->
<select id="selectAllStudentAndClass" resultMap="selectAllStudentAndClassMap">
    select *
    from t_student s
    left join t_class c on s.s_class = c.c_id
    where s.s_id = #{sId}
</select>

2、association标签

association是用来解决多对一映射的标签,对应的映射文件:

<resultMap id="selectAllStudentAndClassMapTwo" type="Student">
    <id property="sId" column="s_id"></id>
    <result property="sName" column="s_name"></result>
    <result property="sAge" column="s_age"></result>
    <result property="sSex" column="s_sex"></result>
    <result property="sEmail" column="s_email"></result>
    <association property="sClass" javaType="cClass">
        <id property="cId" column="c_id"></id>
        <result property="cName" column="c_name"></result>
    </association>
</resultMap>
<!--    List<Student> selectAllStudentAndClass(@Param("sId") Integer sId);-->
<select id="selectAllStudentAndClass" resultMap="selectAllStudentAndClassMapTwo">
    select *
    from t_student s
    left join t_class c on s.s_class = c.c_id
    where s.s_id = #{sId}
</select>

association中的property属性代表实体类中的属性名,javaType代表该属性的类型。

3、分步查询

对应的映射文件:

<resultMap id="selectAllStudentByStepMap" type="Student">
    <id property="sId" column="s_id"></id>
    <result property="sName" column="s_name"></result>
    <result property="sAge" column="s_age"></result>
    <result property="sSex" column="s_sex"></result>
    <result property="sEmail" column="s_email"></result>
    <association property="sClass"
                 select="mappers.ClassMapper.selectById"
                 column="s_class">
    </association>
</resultMap>
<!--    Student selectAllStudentByStep(@Param("sId") Integer sId);-->
<select id="selectAllStudentByStep" resultMap="selectAllStudentByStepMap">
    select *
    from t_student
    where s_id = #{sId}
</select>

也就是先查基本属性,在调用班级接口函数查班级属性。注意association中的column标签要填写数据库中的逻辑外键字段名(等价于第二步查询时传入的参数)。官方文档解释为:

The column name from the database, or the aliased column label that holds the value that will be passed to the nested statement as an input parameter. This is the same string that would normally be passed to resultSet.getString(columnName). Note: To deal with composite keys, you can specify multiple column names to pass to the nested select statement by using the syntax column=“{prop1=col1,prop2=col2}”. This will cause prop1 and prop2 to be set against the parameter object for the target nested select statement

数据库中的列名,或保存将作为输入参数传递给嵌套语句的值的别名列标签。这个字符串与通常传递给 result Set.getString (column nName)的字符串相同。注意: 要处理复合键,可以使用语法 column = “{ prop1 = col1,prop2 = col2}”指定多个列名来传递给嵌套的 select 语句。这将导致将 prop1和 prop2设置为目标嵌套 select 语句的参数对象。

第二步所调用的查询语句:

<!--    int selectById(@Param("cId") Integer cId);-->
<select id="selectById" resultType="cClass">
    select *
    from t_class
    where c_id = #{cId}
</select>

7.3、解决一对多的映射

上面提到的班级信息的多个字段要存放在一个学生实体类属性中,叫做多对一映射。

那一个班级实体类属性中要存放多个学生记录,叫做一对多映射。

这里采用在班级实体类中设置一个List集合来存放学生。

在这里插入图片描述

两种映射方法:

1、collection标签

对应的映射文件:

<resultMap id="selectClassByIdMap" type="cClass">
    <id property="cId" column="c_id"></id>
    <result property="cName" column="c_name"></result>
    <collection property="students" ofType="Student">
        <id property="sId" column="s_id"></id>
        <result property="sName" column="s_name"></result>
        <result property="sAge" column="s_age"></result>
        <result property="sSex" column="s_sex"></result>
        <result property="sEmail" column="s_email"></result>
    </collection>
</resultMap>
<!--        cClass selectClassById(@Param("cId") Integer cId);-->
<select id="selectClassById" resultMap="selectClassByIdMap">
    select *
    from t_class c
    left join t_student s on c.c_id = s.s_class
    where c.c_id = #{cId}
</select>

要注意区分collection和association的区别,collection用ofType=""标签表示集合中的实体类型。

查询id为1的班级信息,运行结果:

cClass{cId=1, cName='计算机1班', students=[
   Student{sId=1, sName='张三', sAge=20, sSex='男', sEmail='123@qq.com', sClass=null},
   Student{sId=4, sName='赵六', sAge=20, sSex='男', sEmail='123@qq.com', sClass=null}]
      }

2、分步查询

相应的映射文件:

<resultMap id="selectClassByStepMap" type="cClass">
    <id property="cId" column="c_id"></id>
    <result property="cName" column="c_name"></result>
    <collection property="students"
                select="mappers.StudentMapper.selectById"
                column="c_id"></collection>
</resultMap>
<!--    cClass selectClassByStep(@Param("cId") Integer cId);-->
<select id="selectClassByStep" resultMap="selectClassByStepMap">
    select *
    from t_class
    where c_id = #{cId}
</select

调用的第二步查询语句:(注意返回类型为List)

<!-- List<Student> selectById(@Param("sId") Integer sId);-->
<select id="selectById" resultType="Student">
    select *
    from t_student
    where s_class = #{sId}
</select>

7.4、分步查询之延迟加载

可以看到,无论是一对多映射还是多对一映射,都可以用分步查询,其中分步查询有一个优势就是延迟加载,也就是懒汉式加载(用什么加载什么,不用不加载)。

在这里插入图片描述

两种开启方式:

1、配置核心文件

<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>

在MyBatis核心配置文件中添加全局设置,开启延迟加载。

2、fetchType标签

在association或者collection中设置fetchType='lazy'可以达到同样的效果。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值