Mybatis自动映射和手动映射:namespace,resultMap和resultType & 自动映射规则

2022-06-22 09:09:14

Mybatis自动映射和手动映射:namespace,resultMap和resultType & 自动映射规则

最近在使用mybatis时,对于mapper.xml中的<mapper>,手动映射,自动映射有些疑惑,对namespaceresultMapresultType的作用也有点疑惑。

小总结:

  • 映射文件中的namespace是用于绑定Dao接口的,即面向接口编程。当你的namespace绑定接口后,你可以不用写接口实现类,mybatis会通过该绑定自动帮你找到对应要执行的SQL语句。
  • resultMap是Mybatis最强大的元素,支持自定义,而resultType直接返回对象类型,但两者不能同时存在resultMap可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。通过<association><collection分别实现一对一关联一对多关联

mybatis 中自动映射主要有 2 种配置:

  • 一种是全局的配置,对应用中所有的 resultMap 起效,这个是在 mybatis 配置文件(mybatis-config.xml)中进行设置的;

    <settings><settingname="autoMappingBehavior"value="自动映射规则(NONE/PARTIAL/FULL)"/></settings>
  • 另外一种是通过resultMap 的 autoMapping 属性进行配置。mybatis 判断某个 resultMap 是否开启自动映射配置的时候,会先查找自身的 autoMapping 属性,如果这个属性设置值了,就直接用这个属性的值,如果resultMap 元素的 autoMapping 属性没有配置,则走全局配置的自动映射规则。

    <resultMapid="orderModelMap2"type="com.javacode2018.chat05.demo7.model.OrderModel"autoMapping="true"></resultMap>

自动映射小总结:

  1. 所谓自动映射,就是 mybatis 会自动按照列名和 Model 中同名的字段column=property)进行映射赋值,不用手动编写映射规则。但是columnproperty不完全一致时,是否支持自动映射呢?最近在做项目时,为了图方便,javaBean中的属性和数据库表的字段都设置为大写,但是我担心这样的属性命名并不符合javaBean的驼峰命名规范,担心mybatis不能将column和property实现自动映射。但是当我了解了mybatis官网提供的自动映射的解释,我放心了。

这里mybatis的自动映射规则可参照官网:https://mybatis.org/mybatis-3/sqlmap-xml.html#Auto-mapping

When auto-mapping results MyBatis will get the column name andlook for a property with the same name ignoring case. That means that if a column namedID and property namedid are found, MyBatis will set theid property with theID column value.

mybatis在自动映射时,会根据column去寻找忽略大小写的、和column名字保持一致的property,即column=IDproperty=id可以实现自动映射(column,property全转成小写再比较)。

Usuallydatabase columns are named usinguppercase letters and underscores between words andjava properties often follow the camelcase naming covention. To enable the auto-mapping between them set the settingmapUnderscoreToCamelCase to true.

在设计数据库表时,字段通常用大写字母,以及下划线来命名;而对于java属性通常采用驼峰命名法,为了实现两者的自动匹配,这里需要将mapUnderscoreToCamelCase设置为True;

Auto-mapping works even when there is an specific result map. When this happens, for each result map, all columns that are present in the ResultSet that have not a manual mapping will be auto-mapped, then manual mappings will be processed.

在手动映射时,那些未手动配置的column-property对,mybatis会进行自动映射

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

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

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

这里补充一个很容易疏忽的bug:

<selectid="findTrainingManagePersonal"resultMap="baseMap"parameterType="com.dpf.trainingManage.entity.TrainingManagePersonal">
        SELECT * FROM training_management_personnel
        WHERE DEL_STATUS = '0'
        AND ID = #{id}</select>

上面的语句在数据库中有正常查出来,但是会报如下的错误:

Creating anewSqlSessionSqlSession[org.apache.ibatis.session.defaults.DefaultSqlSession@2d24573e] was not registeredfor synchronization because synchronization is not active
JDBCConnection[com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@63ac0733] will not be managed bySpring==>Preparing: select* from training_plan where ID=?AND DEL_STATUS='0'==>Parameters:1(Integer)<==Columns: ID, PNAME, START_TIME, END_TIME, ORGANIZATION_ID, PERSONNEL_ID, PREQUIRE, CREATE_BY, CREATE_DATE, UPDATE_BY, UPDATE_DATE, CREATE_NAME, UPDATE_NAME, DEL_STATUS<==Row:1, wangxiaoxi1,2021-12-1400:00:00,2021-12-1400:00:00,null,null,null,null,null,null,null,null,null,0Closing non transactionalSqlSession[org.apache.ibatis.session.defaults.DefaultSqlSession@2d24573e]2021-12-1417:24:47.457 ERROR16004---[nio-9090-exec-2]o.a.c.c.C.[.[.[.[dispatcherServlet]:Servlet.service()for servlet[dispatcherServlet] in contextwithpath[] threw exception[Request processing failed; nested exception isorg.springframework.dao.DataIntegrityViolationException:Error attemptingtoget column'END_TIME' from resultset.  Cause:java.sql.SQLDataException:Cannot determine value type from string'2021-12-14 00:00:00';Cannot determine value type from string'2021-12-14 00:00:00'; nested exception isjava.sql.SQLDataException:Cannot determine value type from string'2021-12-14 00:00:00']withroot causecom.mysql.cj.exceptions.DataConversionException:Cannot determine value type from string'2021-12-14 00:00:00'

主要原因很可能是在实体类中加入了有参构造,使得mybatis在装配对象时用的是有参构造器``

所以解决思路是:

  • 一是去掉@AllArgConstructor,恢复默认的无参构造器
  • 二是在实体类中手动添加无参构造器,实现方法的重载,否则@AllArgConstructor会创建有参构造器来重写原来的无参构造器

参考

  • Mybatis的namespace作用参考Mybatis的mapper标签 namespace属性说明

  • Mybatis的resultType和resultMap比较参考mybaties中resultMap和resultType的区别

  • Mybatis的resultMap作用参考Mybatis:resultMap的使用总结

    <!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性--><resultMapid="唯一的标识"type="映射的pojo对象"><idcolumn="表的主键字段,或者可以为查询语句中的别名字段"jdbcType="字段类型"property="映射pojo对象的主键属性"/><resultcolumn="表的一个字段(可以为任意表的一个字段)"jdbcType="字段类型"property="映射到pojo对象的一个属性(须为type定义的pojo对象中的一个属性)"/><associationproperty="pojo的一个对象属性"javaType="pojo关联的pojo对象"><idcolumn="关联pojo对象对应表的主键字段"jdbcType="字段类型"property="关联pojo对象的主席属性"/><resultcolumn="任意表的字段"jdbcType="字段类型"property="关联pojo对象的属性"/></association><!-- 集合中的property须为oftype定义的pojo对象的属性--><collectionproperty="pojo的集合属性"ofType="集合中的pojo对象"><idcolumn="集合中pojo对象对应的表的主键字段"jdbcType="字段类型"property="集合中pojo对象的主键属性"/><resultcolumn="可以为任意表的字段"jdbcType="字段类型"property="集合中的pojo对象的属性"/></collection></resultMap>
  • Mybatis自动映射参考Mybatis手动映射和自动映射

  • 作者:王小希ww
  • 原文链接:https://blog.csdn.net/qq_33934427/article/details/121674268
    更新时间:2022-06-22 09:09:14