`

MyBatis原理(2)-执行流程 2

 
阅读更多

@Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

@Override
  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    return delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql);
  }



BaseExecutor#createCacheKey
@Override
  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {[size=x-small][/size]
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    CacheKey cacheKey = new CacheKey();
    cacheKey.update(ms.getId());
    cacheKey.update(rowBounds.getOffset());
    cacheKey.update(rowBounds.getLimit());
    cacheKey.update(boundSql.getSql());
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
    // mimic DefaultParameterHandler logic
    for (ParameterMapping parameterMapping : parameterMappings) {
      if (parameterMapping.getMode() != ParameterMode.OUT) {
        Object value;
        String propertyName = parameterMapping.getProperty();
        if (boundSql.hasAdditionalParameter(propertyName)) {
          value = boundSql.getAdditionalParameter(propertyName);
        } else if (parameterObject == null) {
          value = null;
        } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
          value = parameterObject;
        } else {
          MetaObject metaObject = configuration.newMetaObject(parameterObject);
          value = metaObject.getValue(propertyName);
        }
        cacheKey.update(value);
      }
    }
    if (configuration.getEnvironment() != null) {
      // issue #176
      cacheKey.update(configuration.getEnvironment().getId());
    }
    return cacheKey;
  }

根据参数值,RowBounds,ParameterMapping确定缓存Key,每次update会更新Cachekey中的属性,equals的时候会比较各个字段的值,如果两次查询所传入的参数值,ParameterMapping都相等那么就是相同的cacheKey。
 public void update(Object object) {
    int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object); 

    count++;
    checksum += baseHashCode;
    baseHashCode *= count;

    hashcode = multiplier * hashcode + baseHashCode;

    updateList.add(object);
  }
 @Override
  public boolean equals(Object object) {
    if (this == object) {
      return true;
    }
    if (!(object instanceof CacheKey)) {
      return false;
    }

    final CacheKey cacheKey = (CacheKey) object;

    if (hashcode != cacheKey.hashcode) {
      return false;
    }
    if (checksum != cacheKey.checksum) {
      return false;
    }
    if (count != cacheKey.count) {
      return false;
    }

    for (int i = 0; i < updateList.size(); i++) {
      Object thisObject = updateList.get(i);
      Object thatObject = cacheKey.updateList.get(i);
      if (!ArrayUtil.equals(thisObject, thatObject)) {
        return false;
      }
    }
    return true;
  }


createCacheKey方法在Excutor接口定义由BaseExecutor实现,Executor接口的继承接口如下:
[img]
http://my.iteye.com/admin/picture/138355
[/img]
除CachingExecutor之外直接实现Excutor,其他接口均是继承自BaseExcutor,而CachingExecutor只是对其他Executor进行包装:
public class CachingExecutor implements Executor {

  private final Executor delegate;
  //二级事务缓存
  private final TransactionalCacheManager tcm = new TransactionalCacheManager();

  public CachingExecutor(Executor delegate) {
    this.delegate = delegate;
    delegate.setExecutorWrapper(this);
  }



@Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
   //此处获取的是SynchronizedCache的实例,在装饰的对象缓存方法加上Synchronized,二级缓存
    Cache cache = ms.getCache();
    if (cache != null) {
      flushCacheIfRequired(ms);
    //只有对结果处理器为空的才使用二级缓存 //TODO为什么
      if (ms.isUseCache() && resultHandler == null) {
       //parameterMapping只允许存在IN类型的参数映射
        ensureNoOutParams(ms, boundSql);
        @SuppressWarnings("unchecked")
       //获取事务缓存(二级缓存//TODO)
        List<E> list = (List<E>) tcm.getObject(cache, key);
       //缓存为空则委托子类(SimpleExecutor查询),否则直接返回二级缓存结果
        if (list == null) {
         //BaseExecutor#query
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);


  }

此处获取默认缓存是SynchronizedCache,原因是在XMLMapperBuilder#cacheElement解析<cache>节点构建缓存,调用BuilderAssistant#useNewCache,下面是构建缓存链的几个重要的流程:
public Cache useNewCache(Class<? extends Cache> typeClass,
      Class<? extends Cache> evictionClass,
      Long flushInterval,
      Integer size,
      boolean readWrite,
      boolean blocking,
      Properties props) {
    //缓存id为当前xml命名空间
    Cache cache = new CacheBuilder(currentNamespace)
         //没指定实现默认使用PerpetualCache,内部是HashMap
        .implementation(valueOrDefault(typeClass, PerpetualCache.class))
       //没指定过期装饰器默认使用最近最少使用LRUCache对PerpetualCache进行装饰
        .addDecorator(valueOrDefault(evictionClass, LruCache.class))
        .clearInterval(flushInterval)
        .size(size)
        .readWrite(readWrite)
        .blocking(blocking)
        .properties(props)
        .build();
    //添加到配置configuration
    configuration.addCache(cache);
   //设置当前缓存以便为MapperStatement使用
    currentCache = cache;
    return cache;
  }


  public Cache build() {
    setDefaultImplementations();
   //构造PerpetualCache
    Cache cache = newBaseCacheInstance(implementation, id);
    setCacheProperties(cache);
    // issue #352, do not apply decorators to custom caches
    if (PerpetualCache.class.equals(cache.getClass())) {
       //添加底层基础装饰器PerpetualCache为第一层,LruCache为第二层
      for (Class<? extends Cache> decorator : decorators) {
     
        cache = newCacheDecoratorInstance(decorator, cache);
       //给LruCache设置相应属性,主要是size,默认1024
        setCacheProperties(cache);
      }
     //设置装饰器链
      cache = setStandardDecorators(cache);
    } else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
      cache = new LoggingCache(cache);
    }
    return cache;
  }
 //设置默认实现和默认最下层的装饰器
  private void setDefaultImplementations() {
    if (implementation == null) {
      implementation = PerpetualCache.class;
      if (decorators.isEmpty()) {
        decorators.add(LruCache.class);
      }
    }
  }

  private Cache setStandardDecorators(Cache cache) {
    try {
     //再次检查是否设置上
      MetaObject metaCache = SystemMetaObject.forObject(cache);
      if (size != null && metaCache.hasSetter("size")) {
        metaCache.setValue("size", size);
      }
      if (clearInterval != null) {
       //添加过期feature
        cache = new ScheduledCache(cache);
        ((ScheduledCache) cache).setClearInterval(clearInterval);
      }
      if (readWrite) {
       //开启readWrite只能将实现了Serializable的对象添加到缓存
        cache = new SerializedCache(cache);
      }
     //日志记录缓存命中率
      cache = new LoggingCache(cache);
     //给缓存中add put size方法加上 SynchronizedCache
      cache = new SynchronizedCache(cache);
      if (blocking) {
        //blocking=true,是否阻塞
     //每一个key都对应一把锁,当get的时候请求锁,延迟时间后未获取到锁抛出异常
        cache = new BlockingCache(cache);
      }
      return cache;
    } catch (Exception e) {
      throw new CacheException("Error building standard cache decorators.  Cause: " + e, e);
    }
  }



private void flushCacheIfRequired(MappedStatement ms) {
    //二级缓存
    Cache cache = ms.getCache();
   //MapperBuilderAssistant#292
  //        .flushCacheRequired(valueOrDefault(flushCache, !isSelect))
  //如果没有设置了flushCache ,则查询语句都是默认开启二级缓存,即不清除
    if (cache != null && ms.isFlushCacheRequired()) {      
     //flushCache=true或者是不是select
     //清除当前缓存
      tcm.clear(cache);
    }
  }

单独解释下  tcm.clear(cache)
tcm是CachingExecutor的实例变量也是CachingExecutor被叫做CachingExecutor的原因,既然说到了缓存也说下CachingExecutor:
public class CachingExecutor implements Executor {

  private final Executor delegate;
  private final TransactionalCacheManager tcm = new TransactionalCacheManager();

  public CachingExecutor(Executor delegate) {
    this.delegate = delegate;
    delegate.setExecutorWrapper(this);
  }

  @Override
  public Transaction getTransaction() {
    return delegate.getTransaction();
  }

  @Override
  public void close(boolean forceRollback) {
    try {
      //issues #499, #524 and #573
      if (forceRollback) { 
        tcm.rollback();
      } else {
        tcm.commit();
      }
    } finally {
      delegate.close(forceRollback);
    }
  }

  @Override
  public boolean isClosed() {
    return delegate.isClosed();
  }

  @Override
  public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    flushCacheIfRequired(ms);
    return delegate.update(ms, parameterObject);
  }

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

  @Override
  public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {
    flushCacheIfRequired(ms);
    return delegate.queryCursor(ms, parameter, rowBounds);
  }

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    //二级缓存
    Cache cache = ms.getCache();
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

  @Override
  public List<BatchResult> flushStatements() throws SQLException {
    return delegate.flushStatements();
  }

  @Override
  public void commit(boolean required) throws SQLException {
    delegate.commit(required);
    tcm.commit();
  }

  @Override
  public void rollback(boolean required) throws SQLException {
    try {
      delegate.rollback(required);
    } finally {
      if (required) {
        tcm.rollback();
      }
    }
  }

  private void ensureNoOutParams(MappedStatement ms, BoundSql boundSql) {
    if (ms.getStatementType() == StatementType.CALLABLE) {
      for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
        if (parameterMapping.getMode() != ParameterMode.IN) {
          throw new ExecutorException("Caching stored procedures with OUT params is not supported.  Please configure useCache=false in " + ms.getId() + " statement.");
        }
      }
    }
  }

  @Override
  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    return delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql);
  }

  @Override
  public boolean isCached(MappedStatement ms, CacheKey key) {
    return delegate.isCached(ms, key);
  }

  @Override
  public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType) {
    delegate.deferLoad(ms, resultObject, property, key, targetType);
  }

  @Override
  public void clearLocalCache() {
    delegate.clearLocalCache();
  }
  //是否有必要清除缓存,select语句不进行清除,或者表明当前查询需要进行清除
  private void flushCacheIfRequired(MappedStatement ms) {
   //这里获取的是二级缓存
    Cache cache = ms.getCache();
    if (cache != null && ms.isFlushCacheRequired()) {      
      tcm.clear(cache);
    }
  }

  @Override
  public void setExecutorWrapper(Executor executor) {
    throw new UnsupportedOperationException("This method should not be called");
  }

}


TransactionalCacheManager:缓存的事务管理器
TransactionalCacheManager被CachingExecutor持有,默认同一个SQLSession中,所有的
Cache(MapperStatement中的cache 二级缓存),都被这个缓存管理器管理

public class TransactionalCacheManager {
   
  private final Map<Cache, TransactionalCache> transactionalCaches = new HashMap<Cache, TransactionalCache>();
   //清除某个mapper对应的cache或注解声明的cache对应的TransactionalCache
  public void clear(Cache cache) {
    getTransactionalCache(cache).clear();
  }

  public Object getObject(Cache cache, CacheKey key) {
    return getTransactionalCache(cache).getObject(key);
  }
  
  public void putObject(Cache cache, CacheKey key, Object value) {
    getTransactionalCache(cache).putObject(key, value);
  }
  //提交当前事务缓存
  public void commit() {
    for (TransactionalCache txCache : transactionalCaches.values()) {
      txCache.commit();
    }
  }
 //回滚所有事务缓存
  public void rollback() {
    for (TransactionalCache txCache : transactionalCaches.values()) {
      txCache.rollback();
    }
  }

  private TransactionalCache getTransactionalCache(Cache cache) {
    TransactionalCache txCache = transactionalCaches.get(cache);
    if (txCache == null) {
      txCache = new TransactionalCache(cache);
      transactionalCaches.put(cache, txCache);
    }
    return txCache;
  }

}


事务缓存--应该叫缓存事务:TransactionalCache
为底层Cache增加事务功能,简单来说即commit和rollback功能。
commit即将entriesToAddOnCommit提交到底层缓存中,
rollback即回退
public class TransactionalCache implements Cache {

  private static final Log log = LogFactory.getLog(TransactionalCache.class);
  //包装类
  private final Cache delegate;
 //是否在提交的时候清除底层缓存
  private boolean clearOnCommit;
//提交的时候要被添加到缓存中的对象
  private final Map<Object, Object> entriesToAddOnCommit;
//未命中的对象
  private final Set<Object> entriesMissedInCache;

  public TransactionalCache(Cache delegate) {
    this.delegate = delegate;
    //默认false
    this.clearOnCommit = false;
    this.entriesToAddOnCommit = new HashMap<Object, Object>();
    this.entriesMissedInCache = new HashSet<Object>();
  }

  @Override
  public String getId() {
    return delegate.getId();
  }

  @Override
  public int getSize() {
    return delegate.getSize();
  }

  @Override
  public Object getObject(Object key) {
    // issue #116
   //底层缓存获取为空添加到entriesMissedInCache中
    Object object = delegate.getObject(key);
    if (object == null) {
      entriesMissedInCache.add(key);
    }
    // issue #146
    //If a session is closed with no commit/rollback, 2nd level caches should be updated if the session just executed selects
 如果clearOnCommit为true即执行过clear,clear在CachingExcutor中flushCacheIfRequired调用,在调用update方法时flushCacheIfRequired返回true
    if (clearOnCommit) {
      return null;
    } else {
      return object;
    }
  }

  @Override
  public ReadWriteLock getReadWriteLock() {
    return null;
  }
//放入entriesToAddOnCommit等待提交
  @Override
  public void putObject(Object key, Object object) {
    entriesToAddOnCommit.put(key, object);
  }

  @Override
  public Object removeObject(Object key) {
    return null;
  }

//清除待提交,设置标志
  @Override
  public void clear() {
    clearOnCommit = true;
    entriesToAddOnCommit.clear();
  }
   //将当前队列待提交的数据提交到缓存中,并且重新设置标志,清空队列
  public void commit() {
    if (clearOnCommit) {
      delegate.clear();
    }
    flushPendingEntries();
    reset();
  }
  
  public void rollback() {
    unlockMissedEntries();
    reset();
  }

  private void reset() {
    clearOnCommit = false;
    entriesToAddOnCommit.clear();
    entriesMissedInCache.clear();
  }

  private void flushPendingEntries() {
    for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
      delegate.putObject(entry.getKey(), entry.getValue());
    }
   //同时也将未命中的数据在缓存中设置为空
    for (Object entry : entriesMissedInCache) {
      if (!entriesToAddOnCommit.containsKey(entry)) {
        delegate.putObject(entry, null);
      }
    }
  }
 //去掉缓存中未命中的数据
  private void unlockMissedEntries() {
    for (Object entry : entriesMissedInCache) {
      try {
        delegate.removeObject(entry);
      } catch (Exception e) {
        log.warn("Unexpected exception while notifiying a rollback to the cache adapter."
            + "Consider upgrading your cache adapter to the latest version.  Cause: " + e);
      }
    }
  }

}





BaseExecutor#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());
   //使用同一个sqlSession关闭的时候会调用Executor.close
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
//与之前不同的是这里清除的是一级缓存
//queryStack的作用是当多个查询使用的是同一个SqlSession即同一个Executor时,
//这些查询之间是并发进行的,如果后面的某个select语句的flushCache=true会导致其他语句的缓存被清除,即一个flushCache导致其他语句缓存失效,这是应该避免的,所以有且仅仅当当前flushCache=true的语句是当前session的第一个语句或者当前语句总是在当前session最先执行,即可保证其他缓存不被清除
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List<E> list;
    try {
      //每执行一次++1,可判断当前是否能进行缓存清除
      queryStack++;
      //同二级缓存只有在resultHandler为空的情况下一级缓存才保持有效
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) {
       //如果list不为空处理callable语句
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {
       //从数据库获取
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
     //最后执行
      queryStack--;
    }
    //查询完成后执行延迟加载,如果是语句中包含嵌套语句,并且嵌套语句的值已经在一级缓存中,就调用当前Executor的deferLoad生成一个,DeferredLoad包含当前返回结果的MetaObject,objectFactory,resultExtractor等。这里执行load方法就从缓存中获取嵌套的语句值设置给自己,达到加快速度的目的,queryStack=0代表着当前查询结束
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      //如果本地缓存scope 是语句级清除当前缓存
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
    }
    return list;
  }


SimpleExecutor#doQuery
BaseExecutor执行query真正调用的是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();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

Configuration#newStatementHandler 创建StatementHandler

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
   //RoutingStatementHandler是几种StatementHandler的封装
   
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) 
//前面执行了Executor的拦截器,这里执行的是StatementHandler的拦截器,即此处的拦截器被当做StatementHandler
interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

SimpleExecutor#prepareStatement 创建预处理语句,设置参数
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;
  }


BaseExecutor#getConnection
获取Connection对Connection进行动态代理,添加日志功能
 protected Connection getConnection(Log statementLog) throws SQLException {
    Connection connection = transaction.getConnection();
    if (statementLog.isDebugEnabled()) {
      return ConnectionLogger.newInstance(connection, statementLog, queryStack);
    } else {
      return connection;
    }
  }


RoutingStatementHandler#prepare
调用被装饰的SatementHandler的prepare
 public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    return delegate.prepare(connection, transactionTimeout);
  }


BaseStatementHandler#prepare
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);
    }
  }

PreparedStatementHandler#instantiateStatement
@Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
      } else {
        return connection.prepareStatement(sql, keyColumnNames);
      }
    } else if (mappedStatement.getResultSetType() != null) {
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.prepareStatement(sql);
    }
  }


  //PreparedStatementHandler#parameterize
  @Override
  public void parameterize(Statement statement) throws SQLException {
   //BaseStatementHanlder构造方法
   //    this.parameterHandler = configuration.newParameterHandler(mappedStatement, 
  //parameterObject, boundSql);

    parameterHandler.setParameters((PreparedStatement) statement);
  }

//DefaultParameterHandler#setParameters
/**
遍历parameterMappings,获取当前参数中的属性名称,如果boundsql有附加参数,第一优先级为附加参数,如果已经在Configuration中配置了自定义类型处理器,使用自定义类型处理器设置参数,否则使用MetaObject获取参数中的值,最后调用TypeHandler设置参数值,这里的BaseTypeHandler中setParameter调用子类的setNonNullParameter,至此SimpleExecutor的prepareStatement就执行完成了,SimpleExecutor的doQuery方法已经完成了StatementHandler的生成和Statement的生成,下一步就是执行带参数的Statement,
statement被传入StatementHandler(RoutingStatementHandler)的query继续向下委托


**/
 @Override
  public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
      for (int i = 0; i < parameterMappings.size(); i++) {
        ParameterMapping parameterMapping = parameterMappings.get(i);
        if (parameterMapping.getMode() != ParameterMode.OUT) {
          Object value;
          String propertyName = parameterMapping.getProperty();
          if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
            value = boundSql.getAdditionalParameter(propertyName);
          } else if (parameterObject == null) {
            value = null;
          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
            value = parameterObject;
          } else {
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            value = metaObject.getValue(propertyName);
          }
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          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);
          }
        }
      }
    }
  }

PreparedStatementHandler#query

  执行完语句,PreparedStatementHandler回调resultSetHandler的handleResultSets方法,resultSetHandler是在BaseHandler中的构造方法中进行初始化的
 
  this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);


@Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.<E> handleResultSets(ps);
  }



分享到:
评论

相关推荐

    Mybatis常见知识点.md

    - Mybatis SQL执行流程 - Executor的类型 - 什么是延迟加载? - 延迟加载原理 - ${} 和 #{}的区别 - Mybatis 模糊查询LIKE怎么写 - Mybatis是如何获取生成的主键的? - Mybatis动态SQL是什么? - Mybatis插件...

    mybatis-r2dbc:MyBatis R2DBC适配器

    MyBatis R2DBC工作原理对数据CRUD操作SqlSession接口进行Reactive化,对于R2DBC适配来说为ReactiveSqlSessionMapper接口Reactive化,将函数的类型从对象和List调整为Mono和FluxSQL的执行器调整为R2DBC的接口,这里...

    mybatis原理.xmind

    该思维导图主要是对MyBatis原理知识进行了整理,通过对底层的分析,能够实现手写一个实现核心功能的简单MyBats,内容包括MyBatis整体架构和流程的分析、SQL的解析过程、手写解析流程、手写执行流程、看源码、MyBatis...

    SSM框架原理 spring-mvc执行流程

    分类专栏: java框架 文章标签: spring mvc spring mybatis 作用: SSM框架是spring MVC ,... springMVC执行流程: 1. 客户端将请求统一提交到DispatcherServlet; 2. DispatcherServlet会将请求交给HandlerMapping

    mybatis源码流程解析,找工作好帮手

    自己阅读源码及查询资料所写的mybatis源码总结, 包含了mybatis一级缓存、二级缓存,及缓存中常遇到的缓存击穿、缓存雪崩、缓存穿透...挖掘mybatis从配置文件、接口到如何执行sql深层原理;常用的关联查询、嵌套查询等

    动力节点SSM课件源码分析教程配套资料分享

    提高核心竞争力,那么本套视频课程带你深入理解MyBatis、Spring及SpringMVC框架执行流程、底层原理、实现源码,让你对经典流行开源框架做到知其然亦知其所以然,让知识真正地学以致用。 其中有大量一线大厂高频面试...

    最新Java面试题视频网盘,Java面试题84集、java面试专属及面试必问课程

    │ Java面试题48.struts2的执行流程或者struts2的原理.mp4 │ Java面试题49.Struts2的拦截器是什么?你都用它干什么?.mp4 │ Java面试题50.Spring MVC的执行流程.mp4 │ Java面试题51.SpringMVC和Struts2的不同.mp4...

    基于jbpm与activiti的工作流平台技术架构介绍

    宏天BPM X3软件平台是一个易于部署和使用的新一代业务流程管理平台,能够以最快的速度帮助您梳理、设计、执行、监控分析和优化业务流程,从业务和IT相结合的完美视角为用户组建长期而久远的卓越BPM流程管 理架构。...

    Java常见面试题208道.docx

    133.mybatis 分页插件的实现原理是什么? 134.mybatis 如何编写一个自定义插件? 十四、RabbitMQ 135.rabbitmq 的使用场景有哪些? 136.rabbitmq 有哪些重要的角色? 137.rabbitmq 有哪些重要的组件? 138.rabbitmq ...

    涵盖了90%以上的面试题

    hashmap的容量为什么一定要是2的幂呢 TreeMap的底层原理 HashMap,Hashtable和ConcurrentHashMap的区别 在ArrayList和LinkedList尾部添加元素,谁的效率更高 如果HashMap或者hashTable的key是一个自定义的类该怎么办 ...

    基于SpringBoot的公司协同办公平台的设计与实现

    其次,阐述了SpringBoot、MyBatis、EasyUI 等轻量级开源框架的工作原理,对 Maven、MySQL等管理工具的特点进行了分析。再次,分析了系统总体建设范围,通过用例图、流程图等 UML 建模方式,描述了用户可以执行的功能...

    Spring.3.x企业应用开发实战(完整版).part2

     《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练...

    Java-CS-Record:记录准备春招实习过程中,学习与复习的知识(模块化整理,非面试题速成)。注:已拿阿里 offer,暂停更新!

    Java-CS-Record这是一个频繁更新的项目(2020.9 ~ 2021.3)。文章说明这个仓库的文章,都是...目录基础1、Java 核心常见特性源码类型相关特性相关 反射相关问题与源码解析注解底层源码解析 Stream 执行流程源码解析 S

    Spring3.x企业应用开发实战(完整版) part1

     《Spring3.x企业应用开发实战》是在《精通Spring2.x——企业应用开发详解》的基础上,经过历时一年的重大调整改版而成的,本书延续了上一版本追求深度,注重原理,不停留在技术表面的写作风格,力求使读者在熟练...

    idea使用教程2017-06-01.pdf

    Build Execution Deployment(构建执行部署)............................................................ 48 Languages&Frameworks.............................................................................

    JAVA核心知识点整理(有效)

    2. 目录 .........................................................................................................................................................1 JVM ...................................

Global site tag (gtag.js) - Google Analytics