sql语句无非增删改查,对于返回结果,增删改只需知道成功与否,查询就稍稍复杂,我们来看下mybatis如何处理的。在sql的select必须要定义返回resultType或者resultMap,resultType就是一个class对象(HashMap,自定义Java类如City),若返回类型稍稍复杂些就需要ResultMap了,ResultMap的元素:constructor、id、result、association、collection、discriminator。最基本的是id和result:
<resultMap id="cityResultMap" type="City">
<id property="id" column="ID" javaType="long" jdbcType="INTEGER" />
<result property="name" column="Name"/>
<result property="countryCode" column="CountryCode"/>
<result property="district" column="district"/>
<result property="population" column="population"/>
</resultMap>
id和result就是select出的column映射到java对象属性的过程,除了property和column,还有另外三个属性:javaType、jdbcType、typeHandler,javaType和jdbcType一般不需指定(我还不清楚需要指定的情况),先瞧一眼构建出来的ResultMap:
没啥特殊的,构建完直接塞到configuration中去,构建select的MappedStatement时再从configuration取出来,最后在处理ResultSet时再使用(这里能看见一个MappedStatement可对应多个resultMap,暂时没有想到这种使用场景):
先从简单的(只定义id和property的resultMap:cityResultMap,方法->cityDao.getById)开始,继续debug(上图红框),发现会创建一个resultMap的type对象:
创建完对象就该给对象赋值了:
赋值前先check是否要自动mapping,AutoMappingBehavior有Null、Partial、None三个枚举值,默认为Partial,在cityDao.getById调用中,applyAutomaticMappings中并没有做什么,在applyPropertyMappings中,通过propertyMapping挨个通过metaObject给rowValue字段赋值并返回了rowValue,最终结果保存到这里了:
整个流程还是比较简单:拿到resultMap对象->创建返回对象->propertyMappings赋值->typeHandler取值->通过metaObject将返回值set到返回的对象->返回对象保存到DefaultResultHandler中并最终返回List对象。在看下带构造函数的resultMap:
<resultMap id="cityConstructorResultMap" type="CityConstructor">
<constructor>
<idArg column="ID" name="id" javaType="java.lang.Long"/>
<arg column="Name" name="name" javaType="java.lang.String"/>
<arg column="CountryCode" name="countryCode" javaType="java.lang.String"/>
</constructor>
<result property="district" column="district"/>
<result property="population" column="population"/>
</resultMap>
何时回使用呢?当有些字段我并不想提供get方法时(听起来有道理,实际上还没碰见这种case),当resultMap有constructor元素时,创建的返回对象就是调用了带参数的构造函数:
继续看association,它的作用是处理1对1或者说拥有一个XXX,比如一个city,有一个country属性,association有两种方式:Nested Select