千家信息网

mybatis执行器的原理和作用是什么

发表于:2025-12-03 作者:千家信息网编辑
千家信息网最后更新 2025年12月03日,这篇文章主要讲解了"mybatis执行器的原理和作用是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"mybatis执行器的原理和作用是什么"吧!m
千家信息网最后更新 2025年12月03日mybatis执行器的原理和作用是什么

这篇文章主要讲解了"mybatis执行器的原理和作用是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"mybatis执行器的原理和作用是什么"吧!

mytatis执行器主要职责是翻译jdbc操作,是mybatis非常重要的功能

  • 执行器类图如下 cdn.com/2b2669400f9aa8bf71c26dfc09fa90a7cab43762.png">

-从上图中可以看出所有执行器都实现了Executor接口,定义了一些通用的操作,Executor的接口定义如下

/** *    Copyright 2009-2015 the original author or authors. * *    Licensed under the Apache License, Version 2.0 (the "License"); *    you may not use this file except in compliance with the License. *    You may obtain a copy of the License at * *       http://www.apache.org/licenses/LICENSE-2.0 * *    Unless required by applicable law or agreed to in writing, software *    distributed under the License is distributed on an "AS IS" BASIS, *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *    See the License for the specific language governing permissions and *    limitations under the License. */package org.apache.ibatis.executor;import java.sql.SQLException;import java.util.List;import org.apache.ibatis.cache.CacheKey;import org.apache.ibatis.cursor.Cursor;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.reflection.MetaObject;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import org.apache.ibatis.transaction.Transaction;/** * @author Clinton Begin */public interface Executor {  ResultHandler NO_RESULT_HANDLER = null;  int update(MappedStatement ms, Object parameter) throws SQLException;   List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;   List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;   Cursor queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;  List flushStatements() throws SQLException;  void commit(boolean required) throws SQLException;  void rollback(boolean required) throws SQLException;  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);  boolean isCached(MappedStatement ms, CacheKey key);  void clearLocalCache();  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class targetType);  Transaction getTransaction();  void close(boolean forceRollback);  boolean isClosed();  void setExecutorWrapper(Executor executor);}

主要的执行器用四种BatchExecutor,SimpleExecutor,ReuseExecutor,CachingExecutor BatchExecutor 主要的功能处理批理操作

SimpleExecutor 默认执行器处理一般的操作

ReuseExecutor 重复使用,该执行器维护了一个sql与Statement对应关系的一个缓存对像,可以复用Statement

CachingExecutor 缓存执行器,TransactionalCacheManager维护缓存对像,一个本地的HashMap,当使用mybatis缓存时由该执行器负责处理

上面四种执行器除CachingExecutor没有继承BaseExecutor外,基它都继承BaseExecutor基本解析器,CachingExecutor具体执行的时候也是依赖于上面三种执行器,所以看看BaseExecutor做了什么操作

/** *    Copyright 2009-2017 the original author or authors. * *    Licensed under the Apache License, Version 2.0 (the "License"); *    you may not use this file except in compliance with the License. *    You may obtain a copy of the License at * *       http://www.apache.org/licenses/LICENSE-2.0 * *    Unless required by applicable law or agreed to in writing, software *    distributed under the License is distributed on an "AS IS" BASIS, *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *    See the License for the specific language governing permissions and *    limitations under the License. */package org.apache.ibatis.executor;import static org.apache.ibatis.executor.ExecutionPlaceholder.EXECUTION_PLACEHOLDER;import java.sql.Connection;import java.sql.SQLException;import java.sql.Statement;import java.util.List;import java.util.concurrent.ConcurrentLinkedQueue;import org.apache.ibatis.cache.CacheKey;import org.apache.ibatis.cache.impl.PerpetualCache;import org.apache.ibatis.cursor.Cursor;import org.apache.ibatis.executor.statement.StatementUtil;import org.apache.ibatis.logging.Log;import org.apache.ibatis.logging.LogFactory;import org.apache.ibatis.logging.jdbc.ConnectionLogger;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.mapping.ParameterMapping;import org.apache.ibatis.mapping.ParameterMode;import org.apache.ibatis.mapping.StatementType;import org.apache.ibatis.reflection.MetaObject;import org.apache.ibatis.reflection.factory.ObjectFactory;import org.apache.ibatis.session.Configuration;import org.apache.ibatis.session.LocalCacheScope;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import org.apache.ibatis.transaction.Transaction;import org.apache.ibatis.type.TypeHandlerRegistry;/** * @author Clinton Begin */public abstract class BaseExecutor implements Executor {  private static final Log log = LogFactory.getLog(BaseExecutor.class);  protected Transaction transaction;  protected Executor wrapper;  protected ConcurrentLinkedQueue deferredLoads;  protected PerpetualCache localCache;  protected PerpetualCache localOutputParameterCache;  protected Configuration configuration;  protected int queryStack;  private boolean closed;  protected BaseExecutor(Configuration configuration, Transaction transaction) {    this.transaction = transaction;    this.deferredLoads = new ConcurrentLinkedQueue();    this.localCache = new PerpetualCache("LocalCache");    this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");    this.closed = false;    this.configuration = configuration;    this.wrapper = this;  }  @Override  public Transaction getTransaction() {    if (closed) {      throw new ExecutorException("Executor was closed.");    }    return transaction;  }  @Override  public void close(boolean forceRollback) {    try {      try {        rollback(forceRollback);      } finally {        if (transaction != null) {          transaction.close();        }      }    } catch (SQLException e) {      // Ignore.  There's nothing that can be done at this point.      log.warn("Unexpected exception on closing transaction.  Cause: " + e);    } finally {      transaction = null;      deferredLoads = null;      localCache = null;      localOutputParameterCache = null;      closed = true;    }  }  @Override  public boolean isClosed() {    return closed;  }  @Override  public int update(MappedStatement ms, Object parameter) throws SQLException {    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());    if (closed) {      throw new ExecutorException("Executor was closed.");    }    clearLocalCache();    return doUpdate(ms, parameter);  }  @Override  public List flushStatements() throws SQLException {    return flushStatements(false);  }  public List flushStatements(boolean isRollBack) throws SQLException {    if (closed) {      throw new ExecutorException("Executor was closed.");    }    return doFlushStatements(isRollBack);  }  @Override  public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {    BoundSql boundSql = ms.getBoundSql(parameter);    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);    return query(ms, parameter, rowBounds, resultHandler, key, boundSql); }  @SuppressWarnings("unchecked")  @Override  public  List 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.");    }    if (queryStack == 0 && ms.isFlushCacheRequired()) {      clearLocalCache();    }    List list;    try {      queryStack++;      list = resultHandler == null ? (List) 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;  }  @Override  public  Cursor queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {    BoundSql boundSql = ms.getBoundSql(parameter);    return doQueryCursor(ms, parameter, rowBounds, boundSql);  }  @Override  public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class targetType) {    if (closed) {      throw new ExecutorException("Executor was closed.");    }    DeferredLoad deferredLoad = new DeferredLoad(resultObject, property, key, localCache, configuration, targetType);    if (deferredLoad.canLoad()) {      deferredLoad.load();    } else {      deferredLoads.add(new DeferredLoad(resultObject, property, key, localCache, configuration, targetType));    }  }  @Override  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {    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 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;  }  @Override  public boolean isCached(MappedStatement ms, CacheKey key) {    return localCache.getObject(key) != null;  }  @Override  public void commit(boolean required) throws SQLException {    if (closed) {      throw new ExecutorException("Cannot commit, transaction is already closed");    }    clearLocalCache();    flushStatements();    if (required) {      transaction.commit();    }  }  @Override  public void rollback(boolean required) throws SQLException {    if (!closed) {      try {        clearLocalCache();        flushStatements(true);      } finally {        if (required) {          transaction.rollback();        }      }    }  }  @Override  public void clearLocalCache() {    if (!closed) {      localCache.clear();      localOutputParameterCache.clear();    }  }  protected abstract int doUpdate(MappedStatement ms, Object parameter)      throws SQLException;  protected abstract List doFlushStatements(boolean isRollback)      throws SQLException;  protected abstract  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)      throws SQLException;  protected abstract  Cursor doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)      throws SQLException;  protected void closeStatement(Statement statement) {    if (statement != null) {      try {        if (!statement.isClosed()) {          statement.close();        }      } catch (SQLException e) {        // ignore      }    }  }  /**   * Apply a transaction timeout.   * @param statement a current statement   * @throws SQLException if a database access error occurs, this method is called on a closed Statement   * @since 3.4.0   * @see StatementUtil#applyTransactionTimeout(Statement, Integer, Integer)   */  protected void applyTransactionTimeout(Statement statement) throws SQLException {    StatementUtil.applyTransactionTimeout(statement, statement.getQueryTimeout(), transaction.getTimeout());  }  private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) {    if (ms.getStatementType() == StatementType.CALLABLE) {      final Object cachedParameter = localOutputParameterCache.getObject(key);      if (cachedParameter != null && parameter != null) {        final MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter);        final MetaObject metaParameter = configuration.newMetaObject(parameter);        for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {          if (parameterMapping.getMode() != ParameterMode.IN) {            final String parameterName = parameterMapping.getProperty();            final Object cachedValue = metaCachedParameter.getValue(parameterName);            metaParameter.setValue(parameterName, cachedValue);          }        }      }    }  }  private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {    List 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 Connection getConnection(Log statementLog) throws SQLException {    Connection connection = transaction.getConnection();    if (statementLog.isDebugEnabled()) {      return ConnectionLogger.newInstance(connection, statementLog, queryStack);    } else {      return connection;    }  }  @Override  public void setExecutorWrapper(Executor wrapper) {    this.wrapper = wrapper;  }    private static class DeferredLoad {    private final MetaObject resultObject;    private final String property;    private final Class targetType;    private final CacheKey key;    private final PerpetualCache localCache;    private final ObjectFactory objectFactory;    private final ResultExtractor resultExtractor;    // issue #781    public DeferredLoad(MetaObject resultObject,                        String property,                        CacheKey key,                        PerpetualCache localCache,                        Configuration configuration,                        Class targetType) {      this.resultObject = resultObject;      this.property = property;      this.key = key;      this.localCache = localCache;      this.objectFactory = configuration.getObjectFactory();      this.resultExtractor = new ResultExtractor(configuration, objectFactory);      this.targetType = targetType;    }    public boolean canLoad() {      return localCache.getObject(key) != null && localCache.getObject(key) != EXECUTION_PLACEHOLDER;    }    public void load() {      @SuppressWarnings( "unchecked" )      // we suppose we get back a List      List list = (List) localCache.getObject(key);      Object value = resultExtractor.extractObjectFromList(list, targetType);      resultObject.setValue(property, value);    }  }}

从源码中可以看出来,实现了获取Connection,封装返回结果,一些通抽方法的实现,我们在看下SimpleExecutor的简单操作 查询操作

  @Override  public  List 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.query(stmt, resultHandler);    } finally {      closeStatement(stmt);    }  }  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;  }

看到Statement就明白是怎么回事

感谢各位的阅读,以上就是"mybatis执行器的原理和作用是什么"的内容了,经过本文的学习后,相信大家对mybatis执行器的原理和作用是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

0