栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis 自动映射(使用需谨慎)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis 自动映射(使用需谨慎)

什么是自动映射?

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


  
  
  
  


 

  


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





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

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

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





  


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加入配置


  
  

OrderMapper.xml





  

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如下:


  
  



  

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我们不动,还是下面这样,没有手动指定映射规则。


  
  



  

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

mybatis配置


  
  

测试用例

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的映射规则,如下:


  
    
  

再次运行测试用例

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正确了。

autoMapping使用

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

案例1

这个核心配置主要在sqlmap中,如下:


  
    
  



  


对应测试用例

com.javacode2018.chat05.demo7.Demo7Test#getById7

@Test
public 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 t_order a,t_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: 1
24:37.610 [main] INFO  c.j.chat05.demo7.Demo7Test - OrderModel(id=2, userId=1, createTime=1577947790, upTime=1577947790, userModel=UserModel(id=1, name=张学友))

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

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

示例2

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

OrderDetaiMapper.xml加入


  

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

OrderMapper.xml加入