3、MyBatis SQL执行过程

我们已经知道Mapper接口最后实例化的是MapperProxy类型的jdk代理,最终调用的是MapperProxy的invoke方法

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  try {
    if (Object.class.equals(method.getDeclaringClass())) {
      return method.invoke(this, args);
    } else if (isDefaultMethod(method)) {
      return invokeDefaultMethod(proxy, method, args);
    }
  } catch (Throwable t) {
    throw ExceptionUtil.unwrapThrowable(t);
  }
  final MapperMethod mapperMethod = cachedMapperMethod(method);
  return mapperMethod.execute(sqlSession, args);
}
 
 
private MapperMethod cachedMapperMethod(Method method) {
    // methodCache是一个ConcurrentHashMap,key是Method,value是MapperMethod
    // MapperMethod里面包含SqlCommand和MethodSignature
    // SqlCommand是我们调用的方法的名字(类名+方法名),以及类型(select/update/insert/delete)
    // MethodSignature是包括输入参数类型、返回参数类型
  MapperMethod mapperMethod = methodCache.get(method);
  if (mapperMethod == null) {
    mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
    methodCache.put(method, mapperMethod);
  }
  return mapperMethod;
}

org.apache.ibatis.binding.MapperMethod#execute

根据sql语句类型select/update/insert/delete的不同,最终调用sqlSessionTemplate的不同方法,下面以udpate为例

public Object execute(SqlSession sqlSession, Object[] args) {
  Object result;
  switch (command.getType()) {
    case INSERT: {
   Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.insert(command.getName(), param));
      break;
    }
    case UPDATE: {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.update(command.getName(), param));
      break;
    }
    case DELETE: {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.delete(command.getName(), param));
      break;
    }
    case SELECT:
      if (method.returnsVoid() && method.hasResultHandler()) {
        executeWithResultHandler(sqlSession, args);
        result = null;
      } else if (method.returnsMany()) {
        result = executeForMany(sqlSession, args);
      } else if (method.returnsMap()) {
        result = executeForMap(sqlSession, args);
      } else if (method.returnsCursor()) {
        result = executeForCursor(sqlSession, args);
      } else {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = sqlSession.selectOne(command.getName(), param);
      }
      break;
    case FLUSH:
      result = sqlSession.flushStatements();
      break;
    default:
      throw new BindingException("Unknown execution method for: " + command.getName());
  }
  if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
    throw new BindingException("Mapper method '" + command.getName()
        + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
  }
  return result;
}

org.mybatis.spring.SqlSessionTemplate#update(java.lang.String, java.lang.Object)

@Override
public int update(String statement, Object parameter) {
  return this.sqlSessionProxy.update(statement, parameter);
}

从SqlSessionTemplate的构造中可以看出sqlSessionProxy也是一个jdk代理,对应的InvocationHandler是SqlSessionInterceptor

private class SqlSessionInterceptor implements InvocationHandler {
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 创建一个DefaultSqlSession
    SqlSession sqlSession = getSqlSession(
        SqlSessionTemplate.this.sqlSessionFactory,
        SqlSessionTemplate.this.executorType,
        SqlSessionTemplate.this.exceptionTranslator);
    try {
        // 这里调用DefaultSqlSession的update方法
      Object result = method.invoke(sqlSession, args);
        // 如果sqlSession不是由Spring管理的话,这里就会进行事务的提交
      if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
        // force commit even on non-dirty sessions because some databases require
        // a commit/rollback before calling close()
        sqlSession.commit(true);
      }
      return result;
    } catch (Throwable t) {
      Throwable unwrapped = unwrapThrowable(t);
      if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
        // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
        closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        sqlSession = null;
        Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
        if (translated != null) {
          unwrapped = translated;
        }
      }
      throw unwrapped;
    } finally {
      if (sqlSession != null) {
        // 这里其实并没有关闭。
        closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
      }
    }
  }
}

getSqlSession最后都会调用DefaultSqlSessionFactory#openSessionFromDataSource

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  Transaction tx = null;
  try {
    final Environment environment = configuration.getEnvironment();
    // 这里的是在MyBatis初始化过程中提到的SpringManagedTransactionFactory
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
    // 创建一个新的SpringManagedTransaction
    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
    final Executor executor = configuration.newExecutor(tx, execType);
    return new DefaultSqlSession(configuration, executor, autoCommit);
  } catch (Exception e) {
    closeTransaction(tx); // may have fetched a connection so lets call close()
    throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)

根据不同的ExecutorType创建不同的Executor,最后用CachingExecutor对BatchExecutor、ReuseExecutor、SimpleExecutor进行包装,增加了缓存功能,装饰者模式

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
  executorType = executorType == null ? defaultExecutorType : executorType;
  executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
  Executor executor;
  if (ExecutorType.BATCH == executorType) {
    executor = new BatchExecutor(this, transaction);
  } else if (ExecutorType.REUSE == executorType) {
    executor = new ReuseExecutor(this, transaction);
  } else {
    executor = new SimpleExecutor(this, transaction);
  }
    // cacheEnabled默认为true
  if (cacheEnabled) {
    executor = new CachingExecutor(executor);
  }
  executor = (Executor) interceptorChain.pluginAll(executor);
  return executor;
}

继续往下看

org.apache.ibatis.session.defaults.DefaultSqlSession#update(java.lang.String, java.lang.Object)

@Override
public int update(String statement, Object parameter) {
  try {
    // dirty初始化时为false,update更新为ture,commit/rollback/close更新为false
    // 主要是用在非自动提交模式下判断是否需要提交或回滚事物
    dirty = true;
    // 根据类全限定名+方法名获取MappedStatement,比如com.cmb.test.mapper.UserMapper.update
    MappedStatement ms = configuration.getMappedStatement(statement);
    // wrapCollection是对集合类型的参数处理
    // 这里executor类型是org.apache.ibatis.executor.CachingExecutor,包装了SimpleExecutor
    return executor.update(ms, wrapCollection(parameter));
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

org.apache.ibatis.executor.CachingExecutor#update

@Override
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    // 如果我们在mapper.xml中定义了cache节点,或者在update节点上配置flushCache属性为true,就会清除缓存
  flushCacheIfRequired(ms);
    // delete就是SimpleExecutor
  return delegate.update(ms, parameterObject);
}

org.apache.ibatis.executor.BaseExecutor#update

@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.");
  }
    // 清空一级缓存PerpetualCache
  clearLocalCache();
  return doUpdate(ms, parameter);
}

org.apache.ibatis.executor.SimpleExecutor#doUpdate

这里在创建RoutingStatementHandler时,会根据statementType来创建SimpleStatementHandle、PreparedStatementHandler、CallableStatementHandler
statementType默认是PREPARED,可以在mapper.xml的update节点中配置
SimpleStatementHandle:执行简单SQL,不支持预编译
PreparedStatementHandler:支持执行预编译参数的SQL
CallableStatementHandler:用于执行存储过程
RoutingStatementHandler:没有实际操作,用于执行上面3个StatementHandler

@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
  Statement stmt = null;
  try {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
    stmt = prepareStatement(handler, ms.getStatementLog());
    return handler.update(stmt);
  } finally {
    closeStatement(stmt);
  }
}
 
 
// 这里interceptorChain是mybatis的插件集合
// 可以在Executor、StatementHandler、ParameterHandler、ResultSetHandler执行过程中对指定方法进行拦截
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  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) {
 
    // 根据statementType创建不同类型的statementHandler
  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());
  }
 
}

org.apache.ibatis.executor.statement.PreparedStatementHandler#update

@Override
public int update(Statement statement) throws SQLException {
  PreparedStatement ps = (PreparedStatement) statement;
  ps.execute();
  int rows = ps.getUpdateCount();
  Object parameterObject = boundSql.getParameterObject();
  KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
  keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
  return rows;
}

Mybatis SQL执行过程到这里就告一段落了。

你可能感兴趣的:(3、MyBatis SQL执行过程)