版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 初中七年级数学《坐标系与图形面积问题》教学设计
- 1.3《学会自我保护》教学设计-统编版七年级道德与法治下册
- 纺织品文物修复师安全实践考核试卷含答案
- 小学五年级信息科技教学设计:Scratch电子点餐系统的模块化构建与交互逻辑优化
- �沪科版八年级物理《牛顿第一定律》教学设计
- 高中体育与健康必修第一册足球基本战术教学设计
- 初中信息科技八年级物联网新工具自主探究教学设计
- 九年级数学教学设计:三角形内切圆的性质与应用
- 高中一年级综合实践活动教学设计:知震险常备不懈惜生命共护平安地震安全演练主题班会
- 特种动物养殖员标准化能力考核试卷含答案
- 2026年南昌辅警考试试题及答案
- 新版2026-2027学年(新教材)统编版九年级历史下册全册12(教学设计)教案合集83
- 2026年度全国保密教育线上培训题库(选择+判断)及参考答案
- 中国胆囊息肉诊疗指南(2025版)
- 2026年4月自考14166设计表达(环境设计)试题及答案
- 2026西山区人才资源运营管理有限公司招聘西山风景区龙门索道第一批次运营技术人员15人(云南)笔试历年典型考点题库附带答案详解
- 影院场馆安全隐患排查及整改措施
- 建筑工程施工风险评估报告
- 景观工程临时用电方案
- 开口型脚手架施工方案
- 《智能人脸识别系统》课件
评论
0/150
提交评论