(八)MyBatis从入门到入土——自动映射的使用

今天我们介绍一下我们一直在使用的但是没有来得及做过多介绍的自动映射。

什么是自动映射?

介绍自动映射之前先看一下手动映射,如下:

<resultMap id="orderModelMap1" type="com.zhonghu.chat08.demo7.model.OrderModel">    <id column="id" property="id"/>    <result column="userId" property="userId" />    <result column="createTime" property="createTime" />    <result column="upTime" property="upTime" /></resultMap><select id="getById1" resultMap="orderModelMap1">    <![CDATA[    SELECT        a.id,        a.user_id userId,        a.create_time createTime,        a.up_time upTime    FROM        orders a    WHERE        a.id = #{value}    ]]></select>

注意上面的resultMap元素中有4行配置,如下:

<id column="id" property="id"/><result column="userId" property="userId" /><result column="createTime" property="createTime" /><result column="upTime" property="upTime" />

这4行代码用于配置sql结果的列和OrderModel对象中字段的映射关系。

大家有没有注意到,映射规则中column和property元素的值都是一样,mybatis中支持自动映射配置,当开启自动映射之后,当sql的列名和Model中的字段名称是一样的时候(不区分大小写),mybatis内部会进行自动映射,不需要我们手动去写上面的4行映射规则。

下面我们将上面的示例改成自动映射的方式,如下:

<resultMap id="orderModelMap2" type="com.zhonghu.chat08.demo7.model.OrderModel" autoMapping="true"></resultMap><select id="getById2" resultMap="orderModelMap2">    <![CDATA[    SELECT        a.id,        a.user_id userId,        a.create_time createTime,        a.up_time upTime    FROM        orders a    WHERE        a.id = #{value}    ]]></select>

注意上面的resultMap中的autoMapping属性,是否开启自动映射,我们设置为true,这样mybatis会自动按照列名和Model中同名的字段进行映射赋值。

上面两个配置最后查询结果是一样的,都会将查询结果对应的4个字段的值自动赋值给OrderModel中同名的属性。

自动映射开关

mybatis中自动映射主要有2种配置,一种是全局的配置,对应用中所有的resultMap起效,这个是在mybatis配置文件中进行设置的;另外一种是通过resultMap的autoMapping属性进行配置。

mybatis判断某个resultMap是否开启自动映射配置的时候,会先查找自身的autoMapping属性,如果这个属性设置值了,就直接用这个属性的值,如果resultMap元素的autoMapping属性没有配置,则走全局配置的自动映射规则。

下面我们来详解介绍一下这款的内容。

mybatis自动映射全局配置

在mybatis全局配置文件中加入下面配置:

<settings>    <setting name="autoMappingBehavior" value="自动映射规则"/></settings>

主要有一下几种:

  • NONE:关闭全局映射开关

  • PARTIAL:对除在内部定义了嵌套结果映射(也就是连接的属性)以外的属性进行映射,这个也是默认值。

  • FULL:自动映射所有属性。

NONE

当mybatis全局配置中将autoMappingBehavior的值置为了NONE,表示全局自动映射被关闭了,会导致sql实际上有返回结果,但是结果映射的时候不会自动映射所以返回的时候是空

PARTIAL

会进行自动映射,但是有些复杂的查询映射会在resultMap中嵌套一些映射(如:association,collection),当使用PARTIAL的时候,如果有嵌套映射,则这个嵌套映射不会进行自动映射了。

FULL

自动映射所有属性。

autoMapping使用

上面我们有说过,当在resultMap中指定了autoMapping属性之后,这个resultMap的自动映射就受autoMapping属性的控制,和mybatis中全局映射配置(autoMappingBehavior)行为无关了。

案例1

这个核心配置主要在sqlmap中,如下:
<resultMap id="orderModelMap7" type="com.zhonghu.chat08.demo7.model.OrderModel" autoMapping="true">    <association property="userModel" autoMapping="true">        <id column="user_id" property="id"/>    </association></resultMap><select id="getById7" resultMap="orderModelMap7">    <![CDATA[    SELECT        a.id,        a.user_id userId,        a.create_time createTime,        a.up_time upTime,        b.id as user_id,        b.name    FROM        orders a,user b    WHERE        a.user_id = b.id        AND a.id = #{value}    ]]></select>
对应测试用例
com.zhonghu.chat08.demo7.Demo7Test#getById7@Testpublic void getById7() throws IOException {    this.before("demo7/mybatis-config1.xml");    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);        OrderModel orderModel = mapper.getById7(2);        log.info("{}", orderModel);    }}
运行输出
24:37.544 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById7 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime, b.id as user_id, b.name FROM orders a,user b WHERE a.user_id = b.id AND a.id = ? 24:37.589 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById7 - ==> Parameters: 2(Integer)24:37.610 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById7 - <==      Total: 124:37.610 [main] INFO  c.j.chat05.demo7.Demo7Test - OrderModel(id=2, userId=1, createTime=1610803573, upTime=1610803573, userModel=UserModel(id=1, name=冢狐))

OrderModel中所有属性都自动映射成功。

自动装配并不是那么好玩,玩不转可能带来一些隐患,我们看一个案例,见下面的示例2。

示例2

根据订单编号,查询出订单信息,顺便查询出订单明细列表。这个我们使用mybatis中的一对多查询。

OrderDetaiMapper.xml加入
<select id="getListByOrderId1" resultType="com.zhonghu.chat08.demo7.model.OrderDetailModel">    <![CDATA[    SELECT        a.id,        a.order_id AS orderId,        a.goods_id AS goodsId,        a.num,        a.total_price AS totalPrice    FROM        order_detail a    WHERE        a.order_id = #{value}    ]]></select>

这个可以根据订单的id,查询出订单关联的明细列表。

OrderMapper.xml加入
<resultMap id="orderModelMap8" type="com.zhonghu.chat08.demo7.model.OrderModel" autoMapping="true">    <collection property="orderDetailModelList" select="com.zhonghu.chat08.demo7.mapper.OrderDetailMapper.getListByOrderId1" column="id"/></resultMap><select id="getById8" resultMap="orderModelMap8">    <![CDATA[    SELECT        a.id,        a.user_id userId,        a.create_time createTime,        a.up_time upTime    FROM        orders a    WHERE a.id = #{value}    ]]></select>
测试用例
com.zhonghu.chat08.demo7.Demo7Test#getById8@Testpublic void getById8() throws IOException {    this.before("demo7/mybatis-config.xml");    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);        OrderModel orderModel = mapper.getById8(1);        log.info("{}", orderModel);    }}
运行输出
11:06.193 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById8 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime FROM orders a WHERE a.id = ? 11:06.229 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById8 - ==> Parameters: 1(Integer)11:06.250 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ====>  Preparing: SELECT a.id, a.order_id AS orderId, a.goods_id AS goodsId, a.num, a.total_price AS totalPrice FROM t_order_detail a WHERE a.order_id = ? 11:06.251 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ====> Parameters: 1(Integer)11:06.255 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - <====      Total: 211:06.256 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById8 - <==      Total: 111:06.256 [main] INFO  c.j.chat05.demo7.Demo7Test - OrderModel(id=null, userId=2, createTime=1610803573, upTime=1610803573, userModel=null, orderDetailModelList=[OrderDetailModel(id=1, orderId=1, goodsId=1, num=2, totalPrice=16.00), OrderDetailModel(id=2, orderId=1, goodsId=1, num=1, totalPrice=16.00)])

注意输出中OrderModel的id属性,怎么是null值?主要是下面这行配置导致的

<collection property="orderDetailModelList" select="com.zhonghu.chat08.demo7.mapper.OrderDetailMapper.getListByOrderId1" column="id"/>

上面这个配置中有个column属性,指定的是id,此时mybatis认为你对id字段手动指定了映射关系,就跳过了对id字段到OrderModel.id属性的自动映射,所以导致OrderModel对象的id属性没有赋值,此时需要我们在orderModelMap8手动指定id的映射规则,如下:

<resultMap id="orderModelMap8" type="com.zhonghu.chat08.demo7.model.OrderModel" autoMapping="true">    <id column="id" property="id" />    <collection property="orderDetailModelList" select="com.zhonghu.chat08.demo7.mapper.OrderDetailMapper.getListByOrderId1" column="id"/></resultMap>

再去运行测试用例就正常了。

总结一下

对于咱们开发来说,自动映射确实可以帮助我们节省一些代码,不过也存在一些隐患,我们希望自己开发的系统是健壮的,建议大家写mapper xml的时候,还是花点时间将映射的配置都给写上去,这样能够杜绝一些隐患,使我们的系统更稳定。

(0)

相关推荐

  • Java学习-Mybatis

    Mybatis Maven依赖: <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependenc ...

  • 小师妹问我:Mybatis常见注解有哪些?

    回复"面试"获取全套面试资料 当下,注解非常流行,以前很长篇的代码,现在基本上一个注解就能搞定. 那,在Mybatis中又有哪些注解呢? Mybatis中的注解基本上都在org.a ...

  • 【java框架】MyBatis(6)--Mapper映射关联(多表查询补充)

    【java框架】MyBatis(6)--Mapper映射关联(多表查询补充)

  • mybatis延迟加载策略

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper        PUBLIC & ...

  • (二)MyBatis从入门到入土——开发一个Mybatis项目

    这是mybatis系列第2篇.没看前文的建议先去[Java冢狐]公众号中查看前文,方便理解和掌握这篇文章主要接着前文介绍了如何创建并使用Mybatis. 实战演练 上一篇文章中我们大体介绍了MyBat ...

  • (三)MyBatis从入门到入土——使用详解

    MyBatis使用详解 上篇我们手动开发了一个MyBatis项目,但是我们仅仅是编写了代码,对于整个项目是如何运行以及每个代码的意义都没有仔细的分析和说明,那么接下来我们就开始分析每个代码的意义以及如 ...

  • (四)Mybatis从入门到入土——别名、配置文件以及引入mapper

    这是mybatis系列第4篇.没看前文的建议先去[Java冢狐]公众号中查看前文,方便理解和掌握 别名 为什么需要使用别名? 在xml文件中有很多需要类完整的类名的地方,十分的冗长,为了减轻我们的工作 ...

  • (五)Mybatis从入门到入土——Mapper接口传参多种方式解析

    这是mybatis系列第5篇. 说到底Mybatis常见的传参形式无非是传递一个参数.Map.Java对象,亦或是多个参数.下面就分别对这些进行讲解和说明. 传递一个参数 传递一个参数相对来说较为简单 ...

  • (六) MyBatis从入门到入土——主键的获取

    这是mybatis系列第六篇.没看前文的建议先去[Java冢狐]公众号中查看前文,方便理解和掌握. 前面五篇把MyBatis的基本用法基本介绍完毕了,强烈推荐大家先把前面五篇看完实际操作完再来看接下来 ...

  • 围棋定式:入门到入土(85)

    我再不更新,大家可能就已经忘了我并不喜欢打中单了.我只是个臭酱油,给AI包鸡包眼包大药那种. 有时候,你永远不知道自己坑会踩在何处.这个系列,想介绍一些从未体验过的定式大坑.本期开始将陆续介绍小目守角 ...

  • 围棋定式:入门到入土(86)

    我真不是忘了这个系列. 我就是懒. 有时候,你永远不知道自己坑会踩在何处.这个系列,想介绍一些从未体验过的定式大坑.本期开始将陆续介绍小目守角的各种变化,这应该是实战中非常实用的系列. 图1 对于黑1 ...

  • 从入门到入土:MySQL完整学习指南,包教包会!

    一 SQL 介绍 SQL(Structured Query Language),语义是结构化语言, 是一门 ANSI 的标准计算机语言,用来访问和操作数据库系统: 二 数据库介绍 2.1 数据库 我们 ...

  • 围棋定式:入门到入土(87)

    还行,自己就鸽了一个礼拜,给自己一朵小红花. 此处应有打赏,谢谢. 有时候,你永远不知道自己坑会踩在何处.这个系列,想介绍一些从未体验过的定式大坑.本期开始将陆续介绍小目守角的各种变化,这应该是实战中 ...