首先了解一下statementHandler职责:主要负责处理MyBatis与JDBC之间Statement的交互,通俗而言就是负责操作Statement对象与数据库之间的交互。其执行过程中主要依赖ParameterHandler和ResultSetHandler进行参数绑定和结果实体类绑定。 下面主要以查询为例,debugger源码层面分析。SQL执行开始皆从SqlSession开始。 此段代码块中涉及到BoundSQL对象,此处简单提一下相关概念,后期有时间专门总结一下BoundSQl. 继续跟进queryFromDatabase方法,该方法主要从数据库中查询数据 继续跟进doQuery方法,发现BaseExecutor抽象类中该方法并没有实体,仅提供一个钩子方法,而是交给其子类实现,这里体现了模板设计模式。 到目前为止,我们发现了StatementHandler对象的来源自Configuration中newStatementHandler方法创建; 最终,我们可以明确地发现StatementHandler对象是由其子类RoutingStatementHandler创建的,那么它创建的具体逻辑又是如何的呢?真相即将浮出水面,我们跟进RoutingStatementHandler的构造函数; 看到一段很熟悉的代码,我们在文章开头已经将其展现出来了。 后面再次调用query方法,即SampleStatementHandler,PrepareStatementHandler,CallableStatementHandler中方法执行结果实体类绑定,这个具体过程解析,后面计划专门有文章总结。 经历上面的跟踪源码,我们可以了解到StatementHandler对象具体的创建过程,以及参数和结果绑定的流程。 新手跟踪源码,若存在错误或者不足之处,希望大佬及时指正!最后,希望大家多多支持,转发,,关注,谢谢。概述
职责
类图
器设计模式的体现,主要有三个实现类:
从源码层面理解RoutingStatementHandler: public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { switch (ms.getStatementType()) { case STATEMENT: delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case PREPARED: delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case CALLABLE: delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; default: throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); } }
源码
该类中针对增删改查存在多个重载方法,以selectList为例;@Override public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { MappedStatement ms = configuration.getMappedStatement(statement); //调用Executor中的query return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
/** * 查询方法,专门提供select执行的方法 */ @Override public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { //获取查询SQL BoundSql boundSql = ms.getBoundSql(parameter); //创建缓存的key,即作为HashMap中的key CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); //执行查询 return query(ms, parameter, rowBounds, resultHandler, key, boundSql); }
BoundSQl对象主要是用于存储SQL语句,以及对应的参数相关对象。
继续调用BaseExcutor中的重载query方法: /** * 执行查询逻辑, * 首先从缓存中获取数据,缓存中有数据则进行处理存储过程; * 如果缓存中没有数据,则交互数据库查询数据,则将查询结果添加到缓存中 */ @SuppressWarnings("unchecked") @Override public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } //如果不是嵌套查询,且动态查询语句中flushCache = true时即<select id= "xx" flushCache = true>才会清空缓存 if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { //嵌套查询层数+1 queryStack++; //首先从一级缓存中进行查询:根据key获取对象 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { //从缓存中获取对象,则进行处理存储过程 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { //否则即缓存中没有对应的数据,则交互数据库从数据库中查询数据 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; }
/** * 交互数据库从数据库中查询数据,再把查询结果添加到缓存中 */ private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; //向缓存中添加占位符,此时缓存中没有真正所需要的查询数据 localCache.putObject(key, EXECUTION_PLACEHOLDER); try { //查询数据库,由其子类实现,获取对应的查询数据 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { //删除占位符 localCache.removeObject(key); } //再将从数据库查询的结果添加到一级缓存中 localCache.putObject(key, list); //处理存储过程 if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; }
/**交互数据库,查询数据*/ protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
StatementHandler对象创建
从BaseExcutor类中跟进其子类SimpleExecutor看doQuery方法如何实现? @Override public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { // 获取环境配置 Configuration configuration = ms.getConfiguration(); //Configuration中获取StatementHandler StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } }
惊喜若现,继续跟进去;
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { //创建StatementHandler StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; }
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { switch (ms.getStatementType()) { case STATEMENT: delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case PREPARED: delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case CALLABLE: delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; default: throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); } }
根据statementType的类型来判断是哪一种StatementHandler的实现,并且RoutingStatementHandler维护了一个delegate对象,通过delegate对象来实现对实际Handler对象的调用。这里涉及到了一个对象MappedStatement。
众所周知,Excutor是主要负责执行对数据库的操作主要执行者,经历上面分析StatementHandler对象的创建过程,下面继续回归到SimpleExectuor中;
获取到StatementHandler之后,首先进入prepareStatement方法,该方法就是为了获取Statement对象,并设置Statement对象中的参数:private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); stmt = handler.prepare(connection, transaction.getTimeout()); handler.parameterize(stmt); return stmt; }
prepare方法负责生成Statement实例对象@Override public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(boundSql.getSql()); Statement statement = null; try { statement = instantiateStatement(connection); setStatementTimeout(statement, transactionTimeout); setFetchSize(statement); return statement; } catch (SQLException e) { closeStatement(statement); throw e; } catch (Exception e) { closeStatement(statement); throw new ExecutorException("Error preparing statement. Cause: " + e, e); } }
parameterize方法用于处理Statement实例对应的参数。此处我们跟进下去,便可以了解ParameterHandler是如何解析参数的过程。@Override public void parameterize(Statement statement) throws SQLException { parameterHandler.setParameters((PreparedStatement) statement); }
此接口只有一个默认实现类DefaultParameterHandler,跟进setParameters方法@Override public void setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); // parameterMappings 就是对 #{} 或者 ${} 里面参数的封装 List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { // 如果是参数化的SQL,便需要循环取出并设置参数的值 for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); // 如果参数类型不是 OUT ,这个类型与 CallableStatementHandler 有关 // 因为存储过程不存在输出参数,所以参数不是输出参数的时候,就需要设置。 if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; // 得到#{} 中的属性名 String propertyName = parameterMapping.getProperty(); // 如果 propertyName 是 Map 中的key if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params // 通过key 来得到 additionalParameter 中的value值 value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { // 如果不是 additionalParameters 中的key,而且传入参数是 null, 则value 就是null value = null; } // 如果 typeHandlerRegistry 中已经注册了这个参数的 Class对象,即它是Primitive 或者是String 的话 else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { // 否则就是 Map MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } // 在通过SqlSource 的parse 方法得到parameterMappings 的具体实现中,我们会得到parameterMappings的typeHandler TypeHandler typeHandler = parameterMapping.getTypeHandler(); // 获取typeHandler 的jdbc type JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } catch (SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
执行完成参数的解析,继续回归到SampleExecutor#doQuery()方法的流程中 @Override public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { // 获取环境配置 Configuration configuration = ms.getConfiguration(); //Configuration中获取StatementHandler StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } }
总结
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算