myabtis源码解析四(mybatis中statement对象的创建)_第1页
myabtis源码解析四(mybatis中statement对象的创建)_第2页
myabtis源码解析四(mybatis中statement对象的创建)_第3页
myabtis源码解析四(mybatis中statement对象的创建)_第4页
myabtis源码解析四(mybatis中statement对象的创建)_第5页
已阅读5页,还剩6页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、myabtis源码解析四(mybatis中statement对象的创建)上一期,我们分析了sql语句的创建过程,接下来,咱们进入到下一个特别重要的对象创建statement对象的创建StatementHandler是一个非常核心接口,不仅要创建合适statement对象,再将参数放到statement对象中,执行sql,处理结果集.可以说这些步骤者B是在statementHandle中实现的,接下来咱们跟着源码一起来分析,还是以查询为例,接着上期的selectOne分析OverridepublicListdoQuery(MappedStatementms,Objectparameter,Row

2、BoundsrowBounds,ResultHandlerresultHandler,BoundSqlboundSql)throwsSQLExc,tionStatementstmt=null;tryConfigurationconfiguration=ms.getConfiguration();StatementHandlerhandler=configuration.newStatementHandler(wrapper,ms,parameter,rowBounds,resultHandler,boundSql);stmt=prepareStatement(handler,ms.getSta

3、tementLog();returnhandler.query(stmt,resultHandler);finallycloseStatement(stmt);publicStatementHandlernewStatementHandler(Executorexecutor,MappedStatementmappedStatement,ObjectparameterObject,RowBoundsrowBounds,ResultHandler创建路由statementStatementHandlerstatementHandler=newRoutingStatementHandler(exe

4、cutor,mappedStatement,parameterObject,rowBounds,resultHandler,boundSql);应用插件到StatementHandler上statementHandler=(StatementHandler)interceptorChain.pluginAll(statementHandler);returnstatementHandler;publicRoutingStatementHandler(Executorexecutor,MappedStatementms,Objectparameter,RowBoundsrowBounds,Res

5、ultHandlerresultHandler,BoundSqlboundSq/根据StatementType创建不同的StatementHandlerswitch(ms.getStatementType()caseSTATEMENT:delegate=newSimpleStatementHandler(executor,ms,parameter,rowBounds,resultHandler,boundSql);break;casePREPARED:delegate=newPreparedStatementHandler(executor,ms,parameter,rowBounds,res

6、ultHandler,boundSql);break;caseCALLABLE:delegate=newCallableStatementHandler(executor,ms,parameter,rowBounds,resultHandler,boundSql);break;default:thrownewExecutorException(Unknownstatementtype:+ms.getStatementType();再来看一下statement的uml图OdStatementHandlefiQl*iBaseStatementHandter0hRDutingStalementHan

7、dlerAJ十0缶PreparedStatementHandlerQhCallableStalementHandlerQhSimpleSUtefnentHandlerimage.png接下来,我们需要设置参数到sql中了JDBC提供了三种Statement接口,分别是Statement、PreparedStatement和CallableStatement。他们的uml图为:image.pngstatement:提供执行的sql语句PreparedStatJment:对输入参数执行动态替换,也就是将之前的?替换为具体的参数CallableStater|ent:用于保存存储过程输出的结果我们来来

8、分析PreparedStatementprivateStatementprepareStatement(StatementHandlerhandler,LogstatementLog)throwsSQLExceptionStatementstmt;获取连接Connectionconnection=getConnection(statementLog);创建Statementstmt=handler.prepare(connection,transaction.getTimeout();设置参数handler.parameterize(stmt);returnstmt;Overridepubli

9、cStatementprepare(Connectionconnection,IntegertransactionTimeout)throwsSQLExceptionErrorContext.instance().sql(boundSql.getSql();Statementstatement=null;try创建statementstatement=instantiateStatement(connection);/设置超时时间setStatementTimeout(statement,transactionTimeout);设置fetchSizesetFetchSize(statement

10、);returnstatement;catch(SQLExceptione)closeStatement(statement);throwe;catch(Exceptione)closeStatement(statement);thrownewExecutorException(Errorpreparingstatement.Cause:+e,e);OverrideprotectedStatementinstantiateStatement(Connectionconnection)throwsSQLExceptionStringsql=boundSql.getSql();/根据条件调用不同的

11、prepareStatement方法创建PreparedStatementif(mappedStatement.getKeyGenerator()instanceofJdbc3KeyGenerator)StringkeyColumnNames=mappedStatement.getKeyColumns();if(keyColumnNames=null)returnconnection.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);elsereturnconnection.prepareStatement(sql,ke

12、yColumnNames);elseif(mappedStatement.getResultSetType()!=null)returnconnection.prepareStatement(sql,mappedStatement.getResultSetType().getValue(),ResultSet.CONCUR_READ_ONLY);elsereturnconnection.prepareStatement(sql);statement创建就是这样,重点看下参数是怎样设置进去的handler.parameterize(stmt)Overridepublicvoidparameter

13、ize(Statementstatement)throwsSQLExceptionparameterHandler.setParameters(PreparedStatement)statement);OverridepublicvoidsetParameters(PreparedStatementps)ErrorContext.instance().activity(settingparameters).object(mappedStatement.getParameterMap().getld();从boundSql中获取参数映射的集合ListparameterMappings=bound

14、Sql.getParameterMappings();if(parameterMappings!=null)遍历获取参数执行处理for(inti=0;iparameterMappings.size();i+)ParameterMappingparameterMapping=parameterMappings.get(i);/判断参数是传入参数还是传出参数if(parameterMapping.getMode()!=ParameterMode.OUT)Objectvalue;/获取属性名StringpropertyName=parameterMapping.getProperty();/检测Bo

15、undSql的additionalParameters是否包含propertyNameif(boundSql.hasAdditionalParameter(propertyName)/issue#448askfirstforadditionalparamsvalue=boundSql.getAdditionalParameter(propertyName);elseif(parameterobject=null)value=null;/检测运行时参数是否有相应的类型解析器elseif(typeHandlerRegistry.hasTypeHandler(parameterObject.getC

16、lass()value=parameterobject;else/为参数对象创建元信息对象MetaObjectmetaObject=configuration.newMetaObject(parameterObject);value=metaObject.getValue(propertyName);TypeHandlertypeHandler=parameterMapping.getTypeHandler();JdbcTypejdbcType=parameterMapping.getJdbcType();if(value=null&jdbcType=null)jdbcType=configu

17、ration.getJdbcTypeForNull();try/typeHandler对ParameterHandler设置参数typeHandler.setParameter(ps,i+1,value,jdbcType);catch(TypeExceptione)thrownewTypeException(Couldnotsetparametersformapping:+parameterMapping+.Cause:+e,e);catch(SQLExceptione)thrownewTypeException(Couldnotsetparametersformapping:+paramet

18、erMapping+.Cause:+e,e);我们来执行一条根据主键查询的sql语句,然后debug运行,看看参数如何设置进去的selectfromryx_accountwhereid=#id*1”仲HprDfMTr11nod*IM,narMncfe*lnuI|dbr1fpiHan:rujr,nfncvonhruirlUa2image.png每一个?都会在parameterMappings集合中生成一个对象属性执行完之后,一条正正的sql就形成了刖制磋:lie恤障o加me關細:d训洛口朮:i曲簾诚断毗述二总矗册厲町瞪:盛1比狗:踰低应:t阳:训讪密心;Q伽=幽当我们执行完sql后就要开始处理查

19、询结果了结果集的处理工作由结果集处理器ResultSetHandler执行ResultSetHandler是一个接口,它只有一个实现类DefaultResultSetHandler。结果集的处理入口方法是handleResultSets,下面来看一下该方法的实现。OverridepublicListquery(Statementstatement,ResultHandlerresultHandler)throwsSQLExceptionPreparedStatementps=(PreparedStatement)statement;ps.execute();returnresultSetHan

20、dler.handleResultSets(ps);OverridepublicListhandleResultSets(Statementstmt)throwsSQLExceptionErrorContext.instance().activity(handlingresults).object(mappedStatement.getld();finalListmultipleResults=newArrayList();intresultSetCount=0;获取第一个结果集ResultSetWrapperrsw=getFirstResultSet(stmt);ListresultMaps

21、=mappedStatement.getResultMaps();intresultMapCount=resultMaps.size();validateResultMapsCount(rsw,resultMapCount);while(rsw!=null&resultMapCountresultSetCount)ResultMapresultMap=resultMaps.get(resultSetCount);/处理结果集handleResultSet(rsw,resultMap,multipleResults,null);/获取下一个结果集rsw=getNextResultSet(stmt

22、);cleanUpAfterHandlingResultSet();resultSetCount+;StringresultSets=mappedStatement.getResultSets();if(resultSets!=null)while(rsw!=null&resultSetCountresultSets.length)ResultMappingparentMapping=nextResultMaps.get(resultSetsresultSetCount);if(parentMapping!=null)StringnestedResultMapld=parentMapping.

23、getNestedResultMapld();ResultMapresultMap=configuration.getResultMap(nestedResultMapld);handleResultSet(rsw,resultMap,null,parentMapping);rsw=getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount+;returncollapseSingleResultList(multipleResults);privateResultSetWrappergetFirstResultSe

24、t(Statementstmt)throwsSQLException获取结果集ResultSetrs=stmt.getResultSet();while(rs=null)/moveforwardtogetthefirstresultsetincasethedriver/doesntreturntheresultsetasthefirstresult(HSQLDB2.1)if(stmt.getMoreResults()rs=stmt.getResultSet();elseif(stmt.getUpdateCount()=-1)/nomoreresults.Mustbenoresultsetbre

25、ak;returnrs!=null?newResultSetWrapper(rs,configuration):null;处理结果集方法privatevoidhandleResultSet(ResultSetWrapperrsw,ResultMapresultMap,ListmultipleResults,ResultMappingparentMapping)throwsSQLExceptiontryif(parentMapping!=null)/处理存储过程的逻辑,多结果集handleRowValues(rsw,resultMap,null,RowBounds.DEFAULT,parentM

26、apping);else这里有个细节注意下,我们可以实现resultHandler接口处理我们自己定义的结果集类型if(resultHandler=null)/构建默认的结果集处理对象DefaultResultHandlerdefaultResultHandler=newDefaultResultHandler(objectFactory);/处理行值方法handleRowValues(rsw,resultMap,defaultResultHandler,rowBounds,null);multipleResults.add(defaultResultHandler.getResultList

27、();else/处理结果集的行数据handleRowValues(rsw,resultMap,resultHandler,rowBounds,null);finally/issue#228(closeresultsets)closeResultSet(rsw.getResultSet();处理行值方法处理行值方法publicvoidhandleRowValues(ResultSetWrapperrsw,ResultMapresultMap,ResultHandlerresultHandler,RowBoundsrowBounds,ResultMappingparentMappinl)throi

28、f(resultMap.hasNestedResultMaps()ensureNoRowBounds();checkResultHandler();处理结果集映射handleRowValuesForNestedResultMap(rsw,resultMap,resultHandler,rowBounds,parentMapping);else处理简单结果映射handleRowValuesForSimpleResultMap(rsw,resultMap,resultHandler,rowBounds,parentMapping);这里注意啊一下,resultHandle是一个接口,我们可以实现自

29、己的类,用来自定义结果集,map,list等等0闪ResultHandler1DefauFtMapResuttHandler.0bObjecftVrappe-rRes-ultWandller0口DefauItResuftHandleirimage.png我们这里已简单结果映射分析为主,privatevoidhandleRowValuesForSimpleResultMap(ResultSetWrapperrsw,ResultMapresultMap,ResultHandlerresultHandler,RowBoundsrowBounds,ResultthrowsSQLExceptionDef

30、aultResultContextresultContext=newDefaultResultContext();/根据RowBounds定位到指定行记录skipRows(rsw.getResultSet(),rowBounds);while(shouldProcessMoreRows(resultContext,rowBounds)&rsw.getResultSet().next()/获取经过鉴别器处理后的ResultMapResultMapdiscriminatedResultMap=resolveDiscriminatedResultMap(rsw.getResultSet(),resu

31、ltMap,null);/从resultSet中获取结果ObjectrowValue=getRowValue(rsw,discriminatedResultMap);/存储结果storeObject(resultHandler,resultContext,rowValue,parentMapping,rsw.getResultSet();privatevoidskipRows(ResultSetrs,RowBoundsrowBounds)throwsSQLExceptionif(rs.getType()!=ResultSet.TYPE_FORWARD_ONLY)if(rowBounds.get

32、Offset()!=RowBounds.NO_ROW_OFFSET)rs.absolute(rowBounds.getOffset();elsefor(inti=0;i0|foundValues;rowValue=foundValues|configuration.isReturnlnstanceForEmptyRow()?rowValue:null;returnrowValue;这个方法一共有三段逻辑,分别是1:创建结果对象2:是否应该自动映射结果集3:根据resultMap节点中配置的映射关系进行映射我们来一一分析下1:创建结果对象privateObjectcreateResultObje

33、ct(ResultSetWrapperrsw,ResultMapresultMap,ResultLoaderMaplazyLoader,StringcolumnPrefix)throwsSQLException重置之前的映射结果this.useConstructorMappings=false;/resetpreviousmappingresultfinalListClassconstructorArgTypes=newArrayListClass();finalListconstructorArgs=newArrayList();/调用重载方法创建结果对象ObjectresultObject

34、=createResultObject(rsw,resultMap,constructorArgTypes,constructorArgs,columnPrefix);if(resultObject!=null&!hasTypeHandlerForResultObject(rsw,resultMap.getType()finalListpropertyMappings=resultMap.getPropertyResultMappings();for(ResultMappingpropertyMapping:propertyMappings)/issuegcode#109&issue#149i

35、f(propertyMapping.getNestedQueryld()!=null&propertyMapping.isLazy()resultObject=configuration.getProxyFactory().createProxy(resultObject,lazyLoader,configuration,objectFactory,constructorArgTypes,constructorArgs);break;this.useConstructorMappings=(resultobject!=null&!constructorArgTypes.isEmpty();/s

36、etcurrentmappingresultreturnresultObject;2:是否应该自动映射结果集,这个就不分析了,伙伴们可以自行分析下3:根据resultMap节点中配置的映射关系进行映射privatebooleanapplyAutomaticMappings(ResultSetWrapperrsw,ResultMapresultMap,MetaObjectmetaObject,StringcolumnPrefix)throwsSQLException/获取UnMappedColumnAutoMapping列表ListautoMapping=createAutomaticMappi

37、ngs(rsw,resultMap,metaObject,columnPrefix);booleanfoundValues=false;if(!autoMapping.isEmpty()for(UnMappedColumnAutoMappingmapping:autoMapping)/通过TypeHandler从结果集中获取指定列的数据finalObjectvalue=mapping.typeHandler.getResult(rsw.getResultSet(),mapping.column);if(value!=null)foundValues=true;if(value!=null|(c

38、onfiguration.isCallSettersOnNulls()&!mapping.primitive)/通过元信息对象设置value到实体类对象的指定字段上metaObject.setValue(perty,value);returnfoundValues;privateListcreateAutomaticMappings(ResultSetWrapperrsw,ResultMapresultMap,MetaObjectmetaObject,StringcolumnPrefix)throwsfinalStringmapKey=resultMap.getId()+

39、:+columnPrefix;/从缓存中获取UnMappedColumnAutoMapping列表ListautoMapping=autoMappingsCache.get(mapKey);/缓存未命中if(autoMapping=null)autoMapping=newArrayList();/从ResultSetWrapper中获取未配置在中的列名finalListunmappedColumnNames=rsw.getUnmappedColumnNames(resultMap,columnPrefix);for(StringcolumnName:unmappedColumnNames)St

40、ringpropertyName=columnName;if(columnPrefix!=null&!columnPrefix.isEmpty()if(columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)/获取不包含列名前缀的属性名propertyName=columnName.substring(columnPrefix.length();elsecontinue;/将下划线形式的列名转成驼峰式,比如AUTHOR_NAME-authorNamefinalStringproperty=metaObject.findPro

41、perty(propertyName,configuration.isMapUnderscoreToCamelCase();if(property!=null&metaObject.hasSetter(property)/检测当前属性是否存在于resultMap中if(resultMap.getMappedProperties().contains(property)continue;/获取属性的类型finalClasspropertyType=metaObject.getSetterType(property);if(typeHandlerRegistry.hasTypeHandler(pr

42、opertyType,rsw.getJdbcType(columnName)/获取类型处理器finalTypeHandlertypeHandler=rsw.getTypeHandler(propertyType,columnName);/封装上面获取到的信息autoMapping集合中autoMapping.add(newUnMappedColumnAutoMapping(columnName,property,typeHandler,propertyType.isPrimitive();elseconfiguration.getAutoMappingUnknownColumnBehavior

43、().doAction(mappedStatement,columnName,property,propertyType);else若property为空,或实体类中无property属性,此时无法完成列名与实体类属性建立映射关系。默认什么都不做configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement,columnName,(property!=null)?property:propertyName,null);/写入缓存autoMappingsCache.put(mapKey,autoMappin

44、g);returnautoMapping;总结下以上步骤从ResultSetWrapper中获取未配置在中的列名遍历获取到的列名列表若列名包含列名前缀,则移除列名前缀,得到属性名将下划线形式的列名转成驼峰式获取属性类型获取类型处理器创建UnMappedColumnAutoMapping对象我们主要看一下第一个步骤publicListgetUnmappedColumnNames(ResultMapresultMap,StringcolumnPrefix)throwsSQLException获取未映射的列名ListunMappedColumnNames=unMappedColumnNamesMap

45、.get(getMapKey(resultMap,columnPrefix);if(unMappedColumnNames=null)加载映射和未映射的列名loadMappedAndUnmappedColumnNames(resultMap,columnPrefix);unMappedColumnNames=unMappedColumnNamesMap.get(getMapKey(resultMap,columnPrefix);returnunMappedColumnNames;privatevoidloadMappedAndUnmappedColumnNames(ResultMapresul

46、tMap,StringcolumnPrefix)throwsSQLExceptionListmappedColumnNames=newArrayList();ListunmappedColumnNames=newArrayList();finalStringupperColumnPrefix=columnPrefix=null?null:columnPrefix.toUpperCase(Locale.ENGLISH);finalSetmappedColumns=prependPrefixes(resultMap.getMappedColumns(),upperColumnPrefix);for

47、(StringcolumnName:columnNames)finalStringupperColumnName=columnName.toUpperCase(Locale.ENGLISH);if(mappedColumns.contains(upperColumnName)mappedColumnNames.add(upperColumnName);elseunmappedColumnNames.add(columnName);mappedColumnNamesMap.put(getMapKey(resultMap,columnPrefix),mappedColumnNames);unMap

48、pedColumnNamesMap.put(getMapKey(resultMap,columnPrefix),unmappedColumnNames);接下来分析一下MyBatis是如何将结果集中的数据填充到已映射的实体类字段中的privatebooleanapplyPropertyMappings(ResultSetWrapperrsw,ResultMapresultMap,MetaObjectmetaObject,ResultLoaderMaplazyLoader,StringcolumnPrefix)thlowsSQ/获取映射的列名finalListmappedColumnNames=rsw.getMappedColumnNames(resultMap,columnPrefix);booleanfoundValues=false;/获取ResultMappingfinalListpropertyMappings=resultMap.getPr

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论