`

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-generator-1.3.2

    在这个场景中,“逆向工程mybatis-generator-1.3.2”指的是对MyBatis Generator 1.3.2版本的源代码或执行流程进行逆向分析。MyBatis Generator(MBG)是一个强大的工具,能够自动生成MyBatis接口和映射器XML文件,...

    Mybatis逆向生成工具mybatis-generator-core-1.3.2.jar包

    这里我们将深入探讨MBG的核心功能、工作原理以及如何使用mybatis-generator-core-1.3.2.jar这个版本来自动化生成代码。 首先,MyBatis Generator基于数据库表结构,通过配置文件指定数据库连接信息、表名以及需要...

    mybatis-3-master.zip

    总的来说,`mybatis-3-master` 源码分析可以帮助我们理解 MyBatis 内部的工作原理,提高我们对 SQL 执行流程、对象映射机制的理解,从而更好地优化数据库操作,提升系统性能。同时,通过阅读源码,开发者还能学习到...

    mybatis-3-mybatis-3.3.0-SNAPSHOT.zip

    在深入探讨MyBatis 3.3.0的源码之前,先了解一下这个框架的基本概念和工作原理。 MyBatis的核心是SqlSession,它是与数据库交互的接口,通过SqlSessionFactory创建。SqlSessionFactory是配置信息的工厂,它会根据...

    mybatis代码自动生成工具mybatis-generator-core-1.3.2

    Mybatis Generator的工作原理基于XML配置文件,开发者需要在配置文件中指定数据库连接信息、表名以及需要生成的代码类型。通过运行一个简单的Java类,该工具会读取配置文件,自动扫描指定的数据库表,然后根据配置...

    mybatis-3-mybatis-3.5.4-src-read.zip

    在本压缩包“mybatis-3-mybatis-3.5.4-src-read.zip”中,包含了作者对MyBatis 3.5.4版本源码的阅读理解,特别进行了关键部分的注解和流程解析,对于学习和深入理解MyBatis的工作原理非常有帮助。 1. **MyBatis架构...

    mybatis-auto-generator-core逆向自动生成

    2. **工作原理** - 数据库连接:MyBatis-Auto-Generator-Core首先需要建立到数据库的连接,通过JDBC获取数据库元数据,包括表名、列名、数据类型等信息。 - 模板引擎:然后,它使用模板引擎(如FreeMarker或...

    Mybatis---从最基础案例带你深入了解“她”

    #### 二、MyBatis的工作原理 MyBatis的核心设计理念在于给予开发者足够的自由度来编写SQL语句,这使得SQL优化变得更为简单易行。与其他一些ORM框架不同,MyBatis不会自动生成SQL语句,而是需要开发者自行编写。这种...

    mybatis-generator-core-1.3.2

    MyBatis Generator 的工作原理是通过读取数据库元数据,根据预设的模板生成对应的 Java 源代码。它支持多种数据库,包括 MySQL、Oracle、SQL Server 等。在使用 MBG 时,我们需要创建一个 XML 配置文件,其中定义了...

    mybatis-3-mybatis-3.4.1源码

    2. **Executor**:执行器负责执行SQL,它是MyBatis的执行核心。它有多种实现,如SimpleExecutor、ReusedExecutor和BatchExecutor,分别对应不同的执行策略。 3. **StatementHandler**:处理SQL语句,包括预编译、...

    mybatis-src-3.2.2.zip

    通过分析和研究mybatis-3.2.2的源码,开发者可以深入了解MyBatis的工作流程,优化自己的代码,甚至为MyBatis贡献新的功能。对于Java开发者来说,深入理解MyBatis源码是提升自身技能和解决问题的重要途径。

    mybatis-3-mybatis-3.1.0.zip

    通过对MyBatis 3.1.0源码的学习,开发者可以深入理解其内部工作流程,如Mapper接口的动态代理实现、XML解析与SQL构建、动态SQL的编译执行等,从而更好地利用MyBatis进行数据库操作,同时也能为自定义扩展和性能优化...

    mybatis-3-mybatis-3.3.0.tar.gz

    在本压缩包 "mybatis-3-mybatis-3.3.0.tar.gz" 中,包含了 MyBatis 的 3.3.0 版本的源码,这对于学习、理解和调试 MyBatis 的工作原理非常有帮助。 MyBatis 的核心设计理念是将 SQL 语句与 Java 代码分离,通过 XML...

    跑通的Mybatis后端源码-WhenToMint

    总之,"跑通的Mybatis后端源码-WhenToMint"项目提供了一个实际运行的Mybatis应用示例,通过学习和分析这个项目,你可以深入理解Mybatis的工作原理,以及如何在实际项目中使用Mybatis进行数据库操作。同时,良好的...

    Mybatis--SQL解析流程图

    通过上述分析,我们可以清晰地了解到Mybatis中SQL解析的整体流程:从创建SqlSessionFactory开始,到打开SqlSession,再到获取Mapper代理对象,最后执行SQL语句并获取结果。这一过程不仅展示了Mybatis强大的SQL解析...

    mybatis-3-mybatis-3.2.3.tar.gz

    MyBatis 是一款著名的Java持久层框架,它简化了数据库操作与Java对象之间的映射,提供了灵活的SQL构建和执行机制。在MyBatis-3.2.3这个版本中,我们可以深入研究其源码,了解其内部工作原理,这对于Java开发者尤其是...

    mybatis-3-mybatis-3.2.6.tar.gz

    MyBatis 3.2.6 版本是该框架的一个历史版本,对于学习MyBatis的源码、理解其工作原理以及对比不同版本间的差异具有重要意义。 在MyBatis 3.2.6中,我们可以关注以下几个核心知识点: 1. SQL映射:MyBatis的核心...

    mybatis视频教学-

    12. **MyBatis 执行流程**:了解 MyBatis 如何解析 XML 或注解,生成 PreparedStatement,执行 SQL,处理结果集,以及事务提交或回滚的过程。 13. **实战项目**:通过一个完整的案例,实践 MyBatis 的集成,包括...

    mybatis-generator-core-1.3.2.zip

    MyBatis Generator的主要工作原理是通过读取数据库元数据,然后根据预设的模板生成相应的Java源代码和XML配置文件。这样,开发者就可以避免手动编写重复性的代码,从而节省大量时间,提高开发效率。 **主要组件和...

    lijie_study-mybatis-3-master.zip

    通过深入研究"Mybatis-3"的源码,我们可以理解其内部的执行流程,例如Executor的执行策略、StatementHandler的预编译和执行过程、ParameterHandler参数绑定的逻辑,以及ResultSetHandler结果集处理的细节。...

Global site tag (gtag.js) - Google Analytics