Mybatis自动映射和手动映射:namespace,resultMap和resultType & 自动映射规则
最近在使用mybatis时,对于mapper.xml
中的<mapper>
,手动映射,自动映射有些疑惑,对namespace
,resultMap
和resultType
的作用也有点疑惑。
小总结:
- 映射文件中的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>
自动映射小总结:
- 所谓自动映射,就是 mybatis 会自动按照列名和 Model 中同名的字段(column=property)进行映射赋值,不用手动编写映射规则。但是
column
和property
不完全一致时,是否支持自动映射呢?最近在做项目时,为了图方便,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=ID
和property=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 setting
mapUnderscoreToCamelCase
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会进行自动映射
在 resultMap 中指定了autoMapping 属性值为 true 时,就会开启自动映射。
设置全局自动映射,需要在mybatis 全局配置文件中设置autoMappingBehavior
写 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手动映射和自动映射