本篇对mybatis从取到数据库数据开始到映射成对象并返回的过程进行了详细的分析。
转换ResultSet成java对象
下面的代码是PreparedStatementHandler中的
@Overridepublic <E> Cursor<E> queryCursor(Statement statement) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;//这里是执行sql并得到ResultSetps.execute();//这里是真正处理ResultSet,将之转换成java对象的地方return resultSetHandler.<E> handleCursorResultSets(ps);}
//resultSetHandler是DefaultResultSetHandler类型的
@Overridepublic List<Object> handleResultSets(Statement stmt) throws SQLException {ErrorContext.instance().activity("handling results").object(mappedStatement.getId());final List<Object> multipleResults = new ArrayList<Object>();int resultSetCount = 0;//把statement中的ResultSet用ResultSetWrapper包装起来(里面有处理类对象的,列名,类名,列名映射等字段)ResultSetWrapper rsw = getFirstResultSet(stmt);//获得mappedStatement中的ResultMaps(这个在初始化configuration的时候就已经生成好了,这里只是取出来)List<ResultMap> resultMaps = mappedStatement.getResultMaps();int resultMapCount = resultMaps.size();//如果rsw不为空,但是resultMapCount小于1就报错(很容易理解,就是有返回结果,但是没有映射,所以mybatis不知道怎么把结果转换成java类,当然就报错了)validateResultMapsCount(rsw, resultMapCount);while (rsw != null && resultMapCount > resultSetCount) {//拿到resultMapResultMap resultMap = resultMaps.get(resultSetCount);//处理ResultSet,将处理好的结果存到multipleResults(具体看下面的函数)handleResultSet(rsw, resultMap, multipleResults, null);//从上面这个函数出来的时候,multipleResults已经是存有结果的list了//若stmt还有下一个ResultSet,则继续循环rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}//若你的mapper配置文件中配了这个ResultSets属性的话就取出来往下面走(不过一般都不会用到,最少LZ到现在还没有用过)String[] resultSets = mappedStatement.getResultSets();if (resultSets != null) {//不常用就不细细分析了,看完这整篇后,你对mybatis已经有了比较清晰的逻辑了while (rsw != null && resultSetCount < resultSets.length) {ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);if (parentMapping != null) {String nestedResultMapId = parentMapping.getNestedResultMapId();ResultMap resultMap = configuration.getResultMap(nestedResultMapId);handleResultSet(rsw, resultMap, null, parentMapping);}rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}}//最后返回结果集return collapseSingleResultList(multipleResults);}//处理过程private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {try {//如果有parentMapping则走下面if (parentMapping != null) {//进行处理handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);} else {//若resultHandler为空则走下面if (resultHandler == null) {//初始化一个DefaultResultHandlerDefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);//进行处理handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);//multipleResults中加defaultResultHandler里面的结果集multipleResults.add(defaultResultHandler.getResultList());} else {//进行处理handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);}}} finally {// issue #228 (close resultsets)//最后关闭ResultSet回到handleResultSetscloseResultSet(rsw.getResultSet());}}//其实最后走的都是这个函数public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {//看是否有嵌套的ResultMap,(比如使用了association, collection标签)if (resultMap.hasNestedResultMaps()) {ensureNoRowBounds();checkResultHandler();//处理嵌套ResultMaphandleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);} else {//处理简单的ResultMap(以这个为例子)handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);}}//处理简单的ResultMapprivate void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();//若有分页,则先跳过前面的行数(因为mybatis自带的分页是内存分页,全部数据都取到服务器在进行分页的)skipRows(rsw.getResultSet(), rowBounds);while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {//若要继续处理列并且resultSet还有列则处理//这步拿到要进行处理的resultmapResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);//获得整行的数据,根据map映射成java对象Object rowValue = getRowValue(rsw, discriminatedResultMap);//把结果存好,存在resultHandler中的list中(DefaultResultHandler中有一个字段 List<Object> list用来存储这个结果)storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());}}
新建对象并赋值
private 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, resultMap.getType())) {final MetaObject metaObject = configuration.newMetaObject(rowValue);boolean foundValues = this.useConstructorMappings;//看是否需要自动映射if (shouldApplyAutomaticMappings(resultMap, false)) {//自动映射,把结果放到metaObject的originalObject也就是rowValue中(具体函数看下方)foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;}//通过属性映射来找foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;foundValues = lazyLoader.size() > 0 || foundValues;//看这段貌似可以在configuration中设置若找不到就实例化一个初始的对象rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null;}//返回解析好的行值return rowValue;}
通过mapping映射属性
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {//这个是自动获取mapping,也是比较重要的函数(下方有具体的分析)List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);boolean foundValues = false;if (autoMapping.size() > 0) {for (UnMappedColumnAutoMapping mapping : autoMapping) {//遍历autoMapping//从resultSet中解析出值//解析的方法很简单,就不跟了,大概就是调用typeHandler中的get函数,取出和列名相对应的值就行了final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);if (value != null) {//value不为空说明找到了foundValues = true;}if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {// gcode issue #377, call setter on nulls (value is not 'found')//找到了就把值设置到 metaObject中的objectWrapper中的object中。其实就是metaObject中的originalObjectmetaObject.setValue(mapping.property, value);}}}//返回是否找到return foundValues;}
获取Mapping
//创建自动映射的mappingprivate List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {final String mapKey = resultMap.getId() + ":" + columnPrefix;看缓存里有没有List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);//没有就自己造if (autoMapping == null) {//存放映射的UnMappedColumnAutoMapping(一个对应一个字段映射)autoMapping = new ArrayList<UnMappedColumnAutoMapping>();//通过resultSetWrapper来创建未映射的字段的映射(具体方法看下面)final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);for (String columnName : unmappedColumnNames) {//轮询unmappedColumnNamesString propertyName = columnName;if (columnPrefix != null && !columnPrefix.isEmpty()) {// When columnPrefix is specified,// ignore columns without the prefix.if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {propertyName = columnName.substring(columnPrefix.length());} else {continue;}}//通过metaObject找到属性final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());//如果属性不为空且有Set方法的话进入方法if (property != null && metaObject.hasSetter(property)) {//查看该字段set的是什么类型final Class<?> propertyType = metaObject.getSetterType(property);//看typeHandlerRegistry有没有处理这种类型的handle,有的话继续if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {//获取TypeHandlerfinal TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);//生成UnMappedColumnAutoMapping放到autoMapping里autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));} else {configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName, property, propertyType);}} else{configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);}}放到cache中autoMappingsCache.put(mapKey, autoMapping);}//返回autoMapping(回到applyAutomaticMappings方法)return autoMapping;}
//ResultSetWrapper类中
public List<String> getUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {//看缓存有没有,没有自己造,有就直接返回List<String> unMappedColumnNames = unMappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));if (unMappedColumnNames == null) {//加载映射和没映射字段loadMappedAndUnmappedColumnNames(resultMap, columnPrefix);unMappedColumnNames = unMappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));}return unMappedColumnNames;}private void loadMappedAndUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {List<String> mappedColumnNames = new ArrayList<String>();List<String> unmappedColumnNames = new ArrayList<String>();final String upperColumnPrefix = columnPrefix == null ? null : columnPrefix.toUpperCase(Locale.ENGLISH);//获取已经映射过的columnfinal Set<String> mappedColumns = prependPrefixes(resultMap.getMappedColumns(), upperColumnPrefix);//轮询里面ResultSetWrapper中的columnNamesfor (String columnName : columnNames) {//转成大写比对final String upperColumnName = columnName.toUpperCase(Locale.ENGLISH);//若mappedColumns中有此columnif (mappedColumns.contains(upperColumnName)) {//加入到mappedColumnNamesmappedColumnNames.add(upperColumnName);} else {//否则放入unmappedColumnNamesunmappedColumnNames.add(columnName);}}//最后将mappedColumnNames放到mappedColumnNamesMapmappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), mappedColumnNames);//最后将unmappedColumnNames放到unMappedColumnNamesMapunMappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), unmappedColumnNames);}
总结
其实就几个重要的点。
1.创建对象
2.获得resultHandle
3.获得mapping
4.获得typeHandle
5.通过handle和mapping给对象赋值,然后把对象存到resultHandle中
6.最后返回