Mybatis源码分析之(五)mapper如何将数据库数据转换成java对象的
生活随笔
收集整理的這篇文章主要介紹了
Mybatis源码分析之(五)mapper如何将数据库数据转换成java对象的
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
本篇對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.最后返回
總結
以上是生活随笔為你收集整理的Mybatis源码分析之(五)mapper如何将数据库数据转换成java对象的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pytorch随笔-6
- 下一篇: python操作excel-openpy