MyBatis源码分析SQL语句执行的完整流程Word文档下载推荐.docx

上传人:b****5 文档编号:16853757 上传时间:2022-11-26 格式:DOCX 页数:17 大小:21.63KB
下载 相关 举报
MyBatis源码分析SQL语句执行的完整流程Word文档下载推荐.docx_第1页
第1页 / 共17页
MyBatis源码分析SQL语句执行的完整流程Word文档下载推荐.docx_第2页
第2页 / 共17页
MyBatis源码分析SQL语句执行的完整流程Word文档下载推荐.docx_第3页
第3页 / 共17页
MyBatis源码分析SQL语句执行的完整流程Word文档下载推荐.docx_第4页
第4页 / 共17页
MyBatis源码分析SQL语句执行的完整流程Word文档下载推荐.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

MyBatis源码分析SQL语句执行的完整流程Word文档下载推荐.docx

《MyBatis源码分析SQL语句执行的完整流程Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《MyBatis源码分析SQL语句执行的完整流程Word文档下载推荐.docx(17页珍藏版)》请在冰豆网上搜索。

MyBatis源码分析SQL语句执行的完整流程Word文档下载推荐.docx

 

(图片来自《深入理解mybatis原理》MyBatis的架构设计以及实例分析)

2SQL执行流程

  MyBatis主要设计目的还是为了让我们在执行SQL时对输入输出的数据的管理更加方便,所以方便的让我们写出SQL和方便的获取SQL的执行结果是MyBatis的核心竞争力。

下面就用一个例子来从源码角度看一下SQL的完整执行流程。

新建配置文件conf.xml:

conf.xml

首先建立数据表,这里就以user表为例:

复制代码

DROPTABLEIFEXISTSuser;

CREATETABLEuser(

idINTNOTNULLPRIMARYKEYAUTO_INCREMENT,

nameVARCHAR(32)NOTNULL,

passwordVARCHAR(32)NOTNULL,

sexint,

emailVARCHAR(32),

phoneVARCHAR(16),

adminVARCHAR(16)

);

然后新建与数据表对应的类User:

User

再新建usre表的配置文件:

userMapper.xml

最后新建测试类:

/**

*MyBatis测试类

*/

publicclassTestMain{

publicstaticvoidmain(String[]args)throwsIOException{

Stringresouce="

conf.xml"

;

InputStreamis=Resources.getResourceAsStream(resouce);

//构建sqlSession工厂

SqlSessionFactorysqlSessionFactory=newSqlSessionFactoryBuilder().build(is);

//获取sqlSession

SqlSessionsession=sqlSessionFactory.openSession();

Useruser;

try{

/**

*第一种方式:

直接执行已映射的SQL语句

Stringstatement="

com.luoxn28.dao.UserDao.getById"

user=session.selectOne(statement,1);

System.out.println(user);

}

finally{

session.close();

*第二种方式:

执行更清晰和类型安全的代码

//UserDaouserDao=session.getMapper(UserDao.class);

//user=userDao.getById

(1);

//System.out.println(user);

}

  由于我们分析的是SQL的执行流程,那就重点关注下user=session.selectOne(statement,1);

这行代码~注意,传进去的参数是1。

  session是DefaultSqlSession类型的,因为sqlSessionFactory默认生成的SqlSession是DefaultSqlSession类型。

selectOne()会调用selectList()。

//DefaultSqlSession类

public<

E>

List<

selectList(Stringstatement,Objectparameter,RowBoundsrowBounds){

MappedStatementms=configuration.getMappedStatement(statement);

//CURD操作是交给Excetor去处理的

returnexecutor.query(ms,wrapCollection(parameter),rowBounds,Executor.NO_RESULT_HANDLER);

}catch(Exceptione){

throwExceptionFactory.wrapException("

Errorqueryingdatabase.Cause:

"

+e,e);

}finally{

ErrorContext.instance().reset();

  在DefaultSqlSession.selectList中的各种CURD操作都是通多Executor进行的,这里executor的类型是CachingExecutor,接着跳转到其中的query方法中。

//CachingExecutor类

query(MappedStatementms,ObjectparameterObject,RowBoundsrowBounds,ResultHandlerresultHandler)throwsSQLException{

BoundSqlboundSql=ms.getBoundSql(parameterObject);

//获取绑定的sql命令,比如"

SELECT*FROMxxx"

CacheKeykey=createCacheKey(ms,parameterObject,rowBounds,boundSql);

returnquery(ms,parameterObject,rowBounds,resultHandler,key,boundSql);

  getBoundSql为了获取绑定的sql命令,在创建完cacheKey之后,就进入到CachingExecutor类中的另一个query方法中。

@Override

query(MappedStatementms,ObjectparameterObject,RowBoundsrowBounds,ResultHandlerresultHandler,CacheKeykey,BoundSqlboundSql)

throwsSQLException{

Cachecache=ms.getCache();

if(cache!

=null){

flushCacheIfRequired(ms);

if(ms.isUseCache()&

&

resultHandler==null){

ensureNoOutParams(ms,parameterObject,boundSql);

@SuppressWarnings("

unchecked"

list=(List<

)tcm.getObject(cache,key);

if(list==null){

list=delegate.<

query(ms,parameterObject,rowBounds,resultHandler,key,boundSql);

tcm.putObject(cache,key,list);

//issue#578and#116

returnlist;

returndelegate.<

  这里真正执行query操作的是SimplyExecutor代理来完成的,接着就进入到了SimplyExecutor的父类BaseExecutor的query方法中。

//SimplyExecutor的父类BaseExecutor类

@SuppressWarnings("

query(MappedStatementms,Objectparameter,RowBoundsrowBounds,ResultHandlerresultHandler,CacheKeykey,BoundSqlboundSql)throwsSQLException{

ErrorContext.instance().resource(ms.getResource()).activity("

executingaquery"

).object(ms.getId());

if(closed){

thrownewExecutorException("

Executorwasclosed."

if(queryStack==0&

ms.isFlushCacheRequired()){

clearLocalCache();

list;

queryStack++;

*localCache是一级缓存,如果找不到就调用queryFromDatabase从数据库中查找

list=resultHandler==null?

(List<

)localCache.getObject(key):

null;

if(list!

handleLocallyCachedOutputParameters(ms,key,parameter,boundSql);

}else{

list=queryFromDatabase(ms,parameter,rowBounds,resultHandler,key,boundSql);

queryStack--;

if(queryStack==0){

for(DeferredLoaddeferredLoad:

deferredLoads){

deferredLoad.load();

//issue#601

deferredLoads.clear();

if(configuration.getLocalCacheScope()==LocalCacheScope.STATEMENT){

//issue#482

  因为是第一次SQL查询操作,所以会调用queryFromDatabase方法来执行查询。

private<

queryFromDatabase(MappedStatementms,Objectparameter,RowBoundsrowBounds,ResultHandlerresultHandler,CacheKeykey,BoundSqlboundSql)throwsSQLException{

localCache.putObject(key,EXECUTION_PLACEHOLDER);

list=doQuery(ms,parameter,rowBounds,resultHandler,boundSql);

localCache.removeObject(key);

localCache.putObject(key,list);

if(ms.getStatementType()==StatementType.CALLABLE){

localOutputParameterCache.putObject(key,parameter);

  从数据库中查询数据,进入到SimplyExecutor中进行操作。

//SimplyExecutor类

doQuery(MappedStatementms,Objectparameter,RowBoundsrowBounds,ResultHandlerresultHandler,BoundSqlboundSql)throwsSQLException{

Statementstmt=null;

Configurationconfiguration=ms.getConfiguration();

StatementHandlerhandler=configuration.newStatementHandler(wrapper,ms,parameter,rowBounds,resultHandler,boundSql);

//子流程1:

SQL查询参数的设置

stmt=prepareStatement(handler,ms.getStatementLog());

//StatementHandler封装了Statement

//子流程2:

SQL查询操作和结果集的封装

returnhandler.<

query(stmt);

closeStatement(stmt);

  注意,在prepareStatement方法中会进行SQL查询参数的设置,也就是咱们最开始传递进来的参数,其值为1。

handler.<

query(stmt)方法中会进行实际的SQL查询操作和结果集的封装(封装成Java对象)。

当流程走到这里时,程序已经压栈有一定深度了,因为接下来程序分析会兵分两路,一方面深入到SQL查询及结果集的设置子流程1中,然后再深入到SQL查询操作和结果集的封装子流程2,因为还会回到这里,所以就来一张调用栈的特写吧:

子流程1:

privateStatementprepareStatement(StatementHandlerhandler,LogstatementLog)throwsSQLException{

Statementstmt;

//获取一个Connection

Connectionconnection=getConnection(statementLog);

stmt=handler.prepare(connection,transaction.getTimeout());

handler.parameterize(stmt);

//设置SQL查询中的参数值

returnstmt;

  通过getConnection方法来获取一个Connection,调用prepare方法来获取一个Statement(这里的handler类型是RoutingStatementHandler,RoutingStatementHandler的prepare方法调用的是PrepareStatementHandler的prepare方法,因为PrepareStatementHandler并没有覆盖其父类的prepare方法,其实最后调用的是BaseStatementHandler中的prepare方法。

是不是绕晕了,那就再看一遍吧:

))。

调用parameterize方法来设置SQL的参数值(这里最后调用的是PrepareStatementHandler中的parameterize方法,而PrepareStatementHandler.parameterize方法调用的是DefaultParameterHandler中的setParameters方法)。

//PrepareStatementHandler类

publicvoidparameterize(Statementstatement)throwsSQLException{

parameterHandler.setParameters((PreparedStatement)statement);

//DefaultParameterHandler类

publicvoidsetParameters(PreparedStatementps){

ErrorContext.instance().activity("

settingparameters"

).object(mappedStatement.getParameterMap().getId());

ParameterMapping>

parameterMappings=boundSql.getParameterMappings();

if(parameterMappings!

for(inti=0;

i<

parameterMappings.size();

i++){

ParameterMappingparameterMapping=parameterMappings.get(i);

if(parameterMapping.getMode()!

=ParameterMode.OUT){

Objectvalue;

StringpropertyName=parameterMapping.getProperty();

if(boundSql.hasAdditionalParameter(propertyName)){//issue#448askfirstforadditionalparams

value=boundSql.getAdditionalParameter(propertyName);

}elseif(parameterObject==null){

value=null;

}elseif(typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())){

value=parameterObject;

MetaObjectmetaObject=configuration.newMetaObject(parameterObject);

value=metaObject.getValue(propertyName);

TypeHandlertypeHandler=parameterMapping.getTypeHandler();

JdbcTypejdbcType=parameterMapping.getJdbcType();

if(value==null&

jdbcType==null){

jdbcType=configuration.getJdbcTypeForNull();

typeHandler.setParameter(ps,i+1,value,jdbcType);

}catch(TypeExceptione){

thrownewTypeException("

Couldnotsetparametersformapping:

+parameterMapping+"

.Cause:

}catch(SQLExceptione){

  到这里为止,已经给Statement设置了最初传递进去的参数(值为1)了,那么接着分析流程2:

流程2:

SQL查询及结果集的设置

//RoutingStat

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 制度规范

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1