Mybatis处理列名—字段名映射(⼀)—驼峰式命名映射在上篇博客-中提到,我们需要分析Mybatis在转换Result到需要的Java业务对象时做的三件事,如下:
1. 解决了数据库列名到Java列名的映射。
2.解决了数据库类型到Java类型的转换⼯作。
3.在转换过程中具备⼀定的容错能⼒。
其实核⼼就是:
1.数据库中的列名怎么和对象中的字段对应起来。
2.数据库中的列的类型怎么转换到合适的Java类型,不引起转换失败。
今天我们先来看第⼀点,数据库中的列名怎么和对象中的字段对应起来。⾸先是⽇常PO(Persistant Object) CityPO,⾥⾯有五个字段。
1 2 3 4 5 6public class CityPO {    Integer id;
Long cityId;
String cityName;    String cityEnName;    String cityPyName;
本次要查询的数据库中的列名如下所⽰。
1 2 3 4 5 6 7 8 9 10 11 12 13mysql> mysql> desc SU_City;
+--------------+-------------+------+-----+-------------------+-----------------------------+
| Field        | Type        | Null | Key | Default          | Extra                      |
+--------------+-------------+------+-----+-------------------+-----------------------------+
| id          | int(11)    | NO  | PRI | NULL              | auto_increment              |
| city_id      | int(11)    | NO  | UNI | NULL              |                            |
| city_name    | varchar(20) | NO  |    |                  |                            |
| city_en_name | varchar(20) | NO  |    |                  |                            |
| city_py_name | varchar(50) | NO  |    |                  |                            |
| create_time  | datetime    | NO  |    | CURRENT_TIMESTAMP |                            |
| updatetime  | datetime    | NO  | MUL | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +--------------+-------------+------+-----+-------------------+-----------------------------+
7rows in set (0.01sec)
我们是按照驼峰式命名,把数据库中的列名对应到了对象的字段名。如下是Mybatis的接⼝类和映射⽂件。
1 2 3 4public interface CityMapper {
CityPO selectCity(int id); }
1 2 3
4 5 6 7 8<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-////DTD Mapper 3.0//EN"
"/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.CityMapper">
<select id="selectCity"resultType="po.CityPO">
select id,city_id,city_name,city_en_name from SU_City where id = #{id}    </select>
8 9    </select> </mapper>
在上⾯的映射⽂件中,namespace指定了这个接⼝类的全限定类名,紧随其后的select代表是select语句,id是接⼝类中函数的名
字,resultType代表了从这条语句中返回的期望类型的类的完全限定名或别名,在此例⼦中是我们的业务对象CityPO的类路径。
主要有三种⽅案
1.驼峰式命名开关,或者不开,数据库列和字段名全⼀致。
2.Select时指定AS。
这篇主要看⼀下第⼀种,附上⽰例和部分源码⾛读。
1.驼峰命名开关。
因为CityPO的列名是完全根据数据库列名驼峰式命名后得到的,因此Mybatis提供了⼀个配置项。开启开配置项后,在匹配时,能够根据数据库列名到对应对应的驼峰式命名后的字段。
1 2 3 4<settings>
<!-- 开启驼峰,开启后,只要数据库字段和对象属性名字母相同,⽆论中间加多少下划线都可以识别 -->    <setting name="mapUnderscoreToCamelCase"value="true"/>
</settings>
我们从源码⾓度解读⼀下,Mybatis处理ResultSet的映射默认都在DefaultResultSetHandler中完成。
处理⾏数据的时候的时候主要在下⾯的函数⾥进⾏,由于我们在映射⽂件中没有定义额外的ResultMa
p,因此会直接进⼊else分⽀的代码。
1 2 3 4 5 6 7 8 9public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
if(resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else{
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
进⼊handleRowValuesForSimpleResultMap中,主要处理函数如下,在这⾥完成了对象的⽣成及赋值。1Object rowValue = getRowValue(rsw, discriminatedResultMap);
在这⾥先创建了对象的实例,然后获取了对象的元信息,为反射赋值做准备。
1 2 3 4 5 6 7 8 9 10 11private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
if(rowValue != null&& !hasTypeHandlerForResultObject(rsw, Type())) {
final MetaObject metaObject = wMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if(shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;      foundValues = lazyLoader.size() > 0|| foundValues;
11 12 13 14 15      foundValues = lazyLoader.size() > 0|| foundValues;
rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null;    }
return rowValue;
}
在applyAutomaticMappings完成了整个过程,我们进去探⼀探。
就是下⾯这个函数创建好了映射关系,这个函数的下半部分是完成赋值的,映射的部分下次会详细分析。
1List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);在这个⽅法⾥,上半部分是⽣成了数据库的列名,在这个函数中到了对应的字段名。
1final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
我们进去看⼀看,它传进了⽣成好的数据库列名,传进了前⾯提到的是否根据驼峰式命名映射开关的值。
事实证明,真的很简单,往下看,就是把下划线都去了。
1 2 3 4 5 6public String findProperty(String name, boolean useCamelCaseMapping) {    if(useCamelCaseMapping) {
name = place("_", "");
}
return findProperty(name);
}
隐隐觉得是不是⼤⼩写不敏感啊,继续往下看,这⾥返回到的字段名。
1 2 3 4 5 6 7 8 9private StringBuilder buildProperty(String name, StringBuilder builder) {    ..........
String propertyName = reflector.findPropertyName(name);
if(propertyName != null) {
builder.append(propertyName);
}
}
return builder;
}
好了,真相⼤⽩,就是⼤⼩写不敏感的。
1 2 3public String findPropertyName(String name) {
(UpperCase(Locale.ENGLISH)); }
所以如果你数据库⾥字段是city_id,city_Id,⼤写I,那么可能会有问题吧,不过仔细想想,谁会吃⼒不讨好⼲这种事情,硬要处理成标准的驼峰式命名也可以啦,不过感觉必要性不⼤。
namespace是干嘛的经过若⼲次中途崩溃,我终于写完了驼峰式命名开关下,我们是如何完成数据库列和字段名的映射的。后⾯的博⽂会继续看看后续两种⽅案以及DDL时对象字段是如何赋值到Sql语句中。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。