• Mybatis 自动映射


    什么是自动映射?

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

    <resultMap id="orderModelMap1" type="com.javacode2018.chat05.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
            t_order 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.javacode2018.chat05.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
            t_order 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>
    

    autoMappingBehavior 值来源于枚举:org.apache.ibatis.session.AutoMappingBehavior,源码:

    public enum AutoMappingBehavior {
    
      /**
       * Disables auto-mapping.
       */
      NONE,
    
      /**
       * Will only auto-map results with no nested result mappings defined inside.
       */
      PARTIAL,
    
      /**
       * Will auto-map result mappings of any complexity (containing nested or otherwise).
       */
      FULL
    }
    
    • NONE:关闭全局映射开关

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

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

    下面我们来演示一下autoMappingBehavior每种配置的效果。

    NONE

    mybatis-config.xml 加入配置

    <settings>
        <!-- 关闭自动映射开关 -->
        <setting name="autoMappingBehavior" value="NONE"/>
    </settings>
    

    OrderMapper.xml

    <resultMap id="orderModelMap4" type="com.javacode2018.chat05.demo7.model.OrderModel">
    </resultMap>
    
    <select id="getById4" resultMap="orderModelMap4">
        <![CDATA[
        SELECT
            a.id,
            a.user_id userId,
            a.create_time createTime,
            a.up_time upTime
        FROM
            t_order a
        WHERE
            a.id = #{value}
        ]]>
    </select>
    

    OrderMapper.java加入

    OrderModel getById4(int id);
    

    测试用例

    com.javacode2018.chat05.demo7.Demo7Test#getById4
    
    @Test
    public void getById4() throws IOException {
        this.before("demo7/mybatis-config1.xml");
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
            OrderModel orderModel = mapper.getById4(2);
            log.info("{}", orderModel);
        }
    }
    

    运行结果

    21:58.821 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById4 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime FROM t_order a WHERE a.id = ? 
    21:58.850 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById4 - ==> Parameters: 2(Integer)
    21:58.868 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById4 - <==      Total: 1
    21:58.868 [main] INFO  c.j.chat05.demo7.Demo7Test - null
    

    从输出中可以看到最后一样输出结果为 null,sql 实际上返回的是有结果的,但是结果映射的时候返回的是空。

    结果解释

    由于 mybatis 全局配置中将 autoMappingBehavior 的值置为了 NONE,表示全局自动映射被关闭了,而 resultMapper 中的 orderModelMap4 没有配置autoMapping 属性,所以最终这个查询结果不会自动映射,所以最后查询结果为 null。

    PARTIAL

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

    mybatis-config.xml加入配置

    <settings>
        <!-- 对除在内部定义了嵌套结果映射(也就是连接的属性)以外的属性进行映射,这个也是autoMappingBehavior的默认值。 -->
        <setting name="autoMappingBehavior" value="PARTIAL"/>
    </settings>
    

    OrderMapper.xml

    <resultMap id="orderModelMap5" type="com.javacode2018.chat05.demo7.model.OrderModel">
    </resultMap>
    
    <select id="getById5" resultMap="orderModelMap5">
        <![CDATA[
        SELECT
            a.id,
            a.user_id userId,
            a.create_time createTime,
            a.up_time upTime
        FROM
            t_order a
        WHERE
            a.id = #{value}
        ]]>
    </select>
    

    OrderMapper.java加入

    OrderModel getById5(int id);
    

    测试用例

    com.javacode2018.chat05.demo7.Demo7Test#getById5
    
    @Test
    public void getById5() throws IOException {
        this.before("demo7/mybatis-config2.xml");
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
            OrderModel orderModel = mapper.getById5(2);
            log.info("{}", orderModel);
        }
    }
    

    运行结果

    28:32.612 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById5 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime FROM t_order a WHERE a.id = ? 
    28:32.648 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById5 - ==> Parameters: 2(Integer)
    28:32.664 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById5 - <==      Total: 1
    28:32.665 [main] INFO  c.j.chat05.demo7.Demo7Test - OrderModel(id=2, userId=1, createTime=1577947790, upTime=1577947790, userModel=null)
    

    OrderModel 中的 4 个属性被自动映射成功了。

    结果解释

    orderModelMap5 中没有指定 autoMapping 属性,所以自动映射会走全局配置的规则,即 PARTIAL,会进行自动映射。

    我们再来看看 PARTIAL 的解释:对除在内部定义了嵌套结果映射(也就是连接的属性)以外的属性进行映射。这句话是什么意思?

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

    通过订单id查询出订单以及订单用户的信息,sqlmap如下:

    <resultMap id="orderModelMap6" type="com.javacode2018.chat05.demo7.model.OrderModel">
        <association property="userModel">
        </association>
    </resultMap>
    
    <select id="getById6" resultMap="orderModelMap6">
        <![CDATA[
        SELECT
            a.id,
            a.user_id userId,
            a.create_time createTime,
            a.up_time upTime
            b.id as user_id,
            b.name
        FROM
            t_order a,t_user b
        WHERE
            a.user_id = b.id
            AND a.id = #{value}
        ]]>
    </select>
    

    OrderModel.java

    package com.javacode2018.chat05.demo7.model;
    
    import lombok.*;
    
    import java.util.List;
    
    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    public class OrderModel {
        private Integer id;
        private Integer userId;
        private Long createTime;
        private Long upTime;
        private UserModel userModel;
    }
    

    内部有个 userModel 属性引用用户对象。

    UserModel.java
    package com.javacode2018.chat05.demo7.model;
    
    import lombok.*;
    
    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserModel {
        private Integer id;
        private String name;
    }
    

    OrderMapper.java中加入

    OrderModel getById6(int id);
    

    测试用例

    com.javacode2018.chat05.demo7.Demo7Test#getById6
    @Test
    public void getById6() throws IOException {
        this.before("demo7/mybatis-config2.xml");
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
            OrderModel orderModel = mapper.getById6(2);
            log.info("{}", orderModel);
        }
    }
    

    运行输出

    52:49.037 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime, b.id as user_id, b.name FROM t_order a,t_user b WHERE a.user_id = b.id AND a.id = ? 
    52:49.066 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==> Parameters: 2(Integer)
    52:49.087 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - <==      Total: 1
    52:49.088 [main] INFO  c.j.chat05.demo7.Demo7Test - null
    

    sql 查询实际上是有一条记录的,但是最后返回的是 null,说明没有进行自动映射。

    FULL

    自动映射所有属性。

    这次Mapper我们不动,还是下面这样,没有手动指定映射规则。

    <resultMap id="orderModelMap6" type="com.javacode2018.chat05.demo7.model.OrderModel">
        <association property="userModel">
        </association>
    </resultMap>
    
    <select id="getById6" resultMap="orderModelMap6">
        <![CDATA[
        SELECT
            a.id,
            a.user_id userId,
            a.create_time createTime,
            a.up_time upTime
            b.id as user_id,
            b.name
        FROM
            t_order a,t_user b
        WHERE
            a.user_id = b.id
            AND a.id = #{value}
        ]]>
    </select>
    

    修改一下 autoMappingBehavior 的值为 FULL,看看效果。

    mybatis配置

    <settings>
        <!-- 自动映射所有属性 -->
        <setting name="autoMappingBehavior" value="FULL"/>
    </settings>
    

    测试用例

    com.javacode2018.chat05.demo7.Demo7Test#getById6_0
    
    @Test
    public void getById6_0() throws IOException {
        this.before("demo7/mybatis-config3.xml");
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
            OrderModel orderModel = mapper.getById6(2);
            log.info("{}", orderModel);
        }
    }
    

    运行输出

    56:05.127 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime, b.id as user_id, b.name FROM t_order a,t_user b WHERE a.user_id = b.id AND a.id = ? 
    56:05.155 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==> Parameters: 2(Integer)
    56:05.186 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - <==      Total: 1
    56:05.186 [main] INFO  c.j.chat05.demo7.Demo7Test - OrderModel(id=2, userId=1, createTime=1577947790, upTime=1577947790, userModel=UserModel(id=2, name=张学友))
    

    输出中可以看到 OrderModel 所有属性都是有值的,userModel 的 2 个属性也有值,userModel.id 是 2,我们运行一下 sql 看看,用户 id 是多少,如下:

    mysql> SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime, b.id as user_id, b.name FROM t_order a,t_user b WHERE a.user_id = b.id AND a.id = 2;
    +----+--------+------------+------------+---------+-----------+
    | id | userId | createTime | upTime     | user_id | name      |
    +----+--------+------------+------------+---------+-----------+
    |  2 |      1 | 1577947790 | 1577947790 |       1 | 张学友    |
    +----+--------+------------+------------+---------+-----------+
    1 row in set (0.00 sec)
    

    user_id 实际上是 1,mybatis 中按照 sql 字段和 model 结果字段同名进行自动映射,所以将订单的 id 赋值给 userModel 的 id 属性了。

    此时需要我们 orderModelMap6 的配置,手动指定一下 user_id 和 userModel.id 的映射规则,如下:

    <resultMap id="orderModelMap6" type="com.javacode2018.chat05.demo7.model.OrderModel">
        <association property="userModel">
            <id column="user_id" property="id"/>
        </association>
    </resultMap>
    

    再次运行测试用例

    com.javacode2018.chat05.demo7.Demo7Test#getById6_0
    

    输出

    15:02.751 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==>  Preparing: SELECT a.id, a.user_id userId, a.create_time createTime, a.up_time upTime, b.id as user_id, b.name FROM t_order a,t_user b WHERE a.user_id = b.id AND a.id = ? 
    15:02.783 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - ==> Parameters: 2(Integer)
    15:02.801 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById6 - <==      Total: 1
    15:02.801 [main] INFO  c.j.chat05.demo7.Demo7Test - OrderModel(id=2, userId=1, createTime=1577947790, upTime=1577947790, userModel=UserModel(id=1, name=张学友))
    

    这次 userModel 中的 id 正确了。

    总结

    1. 所谓自动映射,就是 mybatis 会自动按照列名和 Model 中同名的字段(column=property)进行映射赋值,不用手动编写映射规则。

    2. 在 resultMap 中指定了 autoMapping 属性值为 true 时,就会开启自动映射。

    3. 设置全局自动映射,需要在 mybatis 全局配置文件中设置 autoMappingBehavior

    4. 写 mapper.xml 的时候,建议将映射的配置都给写上去,这样能够杜绝一些隐患,使我们的系统更稳定。

    参考资源

    1.https://cloud.tencent.com/developer/article/1581433

    每天学习一点点,每天进步一点点。

  • 相关阅读:
    Caused by: java.util.MissingResourceException: Can't find bundle for base name javax.servlet.LocalStrings, locale zh_CN
    java调优
    idea的spring配置
    【从0到1学Web前端】javascript中的ajax对象(一) 分类: JavaScript 2015-06-24 10:18 754人阅读 评论(1) 收藏
    javascript中对条件判断语句的优化 分类: JavaScript 2015-06-07 09:54 832人阅读 评论(2) 收藏
    【从0到1学Web前端】CSS伪类和伪元素 分类: HTML+CSS 2015-06-02 22:29 1065人阅读 评论(0) 收藏
    django中url,静态文件,POST请求的配置 分类: Python 2015-06-01 17:00 789人阅读 评论(0) 收藏
    【从0到1学Web前端】CSS定位问题三(相对定位,绝对定位) 分类: HTML+CSS 2015-05-29 23:01 842人阅读 评论(0) 收藏
    Javascript图片预加载详解 分类: JavaScript HTML+CSS 2015-05-29 11:01 768人阅读 评论(0) 收藏
    【从0到1学Web前端】CSS定位问题二(float和display的使用) 分类: HTML+CSS 2015-05-28 22:03 812人阅读 评论(1) 收藏
  • 原文地址:https://www.cnblogs.com/youcoding/p/15079197.html
Copyright © 2020-2023  润新知