MyBatis原理--插入操作

上一篇中已经解析了配置文件,并创建了DefaultSqlSessionFactory对象,现在来看一下从DefaultSqlSessionFactory对象中创建一个sqlSession并执行一次insert操作的过程。(MyBatis版本:3.2)

首先是获取SqlSession的过程:

public class DefaultSqlSessionFactory implements SqlSessionFactory {
  private final Configuration configuration;
  private final TransactionFactory managedTransactionFactory;

  public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
    this.managedTransactionFactory = new ManagedTransactionFactory();
  }

  public SqlSession openSession() {
    //defaultExecutorType = ExecutorType.SIMPLE
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    try {
      //从environment中获取dataSource和transactionFactory
      final Environment environment = configuration.getEnvironment();
      final DataSource dataSource = getDataSourceFromEnvironment(environment);
      TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      Connection connection = dataSource.getConnection();
      if (level != null) {
        connection.setTransactionIsolation(level.getLevel());
      }

      //如果日志设置到debug级别,则为connection设置代理,并对Statement,PrepareStatement,ResultSet对象设置代理,主要作用也就是获取更多的调试信息,打印更详细的log。
      connection = wrapConnection(connection);
      Transaction tx = transactionFactory.newTransaction(connection, autoCommit);
      Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (SQLException e) {
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //从environment中获取dataSource和transactionFactory
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

      //此处返回SimpleExecutor, executor是sql语句执行的关键。
      final Executor executor = configuration.newExecutor(tx, execType, autoCommit);

      //将生成的executor赋值给sqlSession
      return new DefaultSqlSession(configuration, executor);
    } 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();
    }
  }
}

看一下executor的生成过程:

public class Configuration {
    //ExecutorType用的是默认的,ExecutorType.SIMPLE
  public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
    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);
    }

    //如果使用cache,CachingExeutor对真正的executor做了简单的封装。
    if (cacheEnabled) {
      executor = new CachingExecutor(executor, autoCommit);
    }

    //这里将executor添加到拦截器链中
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }
}

public class InterceptorChain {

  private final List<Interceptor> interceptors = new ArrayList<Interceptor>();

  //该方法中拦截器对executor做了代理,然后后续的拦截器对面前的拦截器做代理。
  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }

}

//MyBatis并没有官方的拦截器,所以无法看到在plugin方法中官方是怎么做的,通常在此方法中会调用Plugin.wrap()方法。
public class Plugin implements InvocationHandler {

  private Object target;
  private Interceptor interceptor;
  private Map<Class<?>, Set<Method>> signatureMap;

  private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
    this.target = target;
    this.interceptor = interceptor;
    this.signatureMap = signatureMap;
  }

  //这里第一个参数是被代理的对象,第二个参数是代理对象。
  //最开始的被代理对象是executor,被拦截器代理,然后拦截器本身也会变成被代理的对象,被后面的拦截器代理
  public static Object wrap(Object target, Interceptor interceptor) {
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
        //这里是真正设置代理的地方
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      Set<Method> methods = signatureMap.get(method.getDeclaringClass());
      if (methods != null && methods.contains(method)) {
        //intercept()方法是代理逻辑具体执行的地方,在被代理对象的method执行前后,或者围绕着被代理对象的method的执行过程,做一些事情。
        return interceptor.intercept(new Invocation(target, method, args));
      }
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }
}

//至此,SqlSession创建过程结束。

下面看一下SqlSesssion执行insert操作的过程:

public class DefaultSqlSession implements SqlSession {

  private Configuration configuration;
  private Executor executor;

  private boolean dirty;


  public DefaultSqlSession(Configuration configuration, Executor executor) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
  }

  public int insert(String statement, Object parameter) {
    return update(statement, parameter);
  }

  public int update(String statement, Object parameter) {
    try {
      dirty = true;
      //此时获取MappedStatement的时候,如果还有未解析的resultMap,parameterMap或者cache,则继续解析。
      MappedStatement ms = configuration.getMappedStatement(statement);

      //如果调用的statement使用了cache,那么会先清除所有cache,然后再交给SimpleExecutor去处理(Executor默认类型是SimpleExecutor)。
      //一个mapper文件中如果声明了cache,那么select操作默认会使用这个cache,insert、update和delete操作默认会刷新这个cache。
      //此处就不再看CacheExecutor的代码了,直接进入SimpleExecutor。SimpleExecutor的update方法继承的是父类BaseExecutor的。
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
}

SimpleExecutor中逻辑:

//先看一眼BaseExecutor中的update方法
  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.");
    //清除一下本地缓存,主要逻辑在doUpdate方法中
    clearLocalCache();
    return doUpdate(ms, parameter);
  }

 //SimpleExecutor
public class SimpleExecutor extends BaseExecutor {
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      //先获取statementHandler
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      //再获取statement
      stmt = prepareStatement(handler, ms.getStatementLog());
      //然后执行
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }
}

//先来看一下Configuration.newStatementHandler
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    //可以看到这边new的是一个RoutingStatementHandler,从名字上就可以看出这家伙不是真正做事情的,是做分发的。
    //所以在RoutingStatementHandler的构造方法中,根据MappedStatement的类型(默认为Prepared类型),构造真正做事情的StatementHandler。
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);

    //statementHandler在此处的待遇和之前的executor一样,都是被interceptor代理。
    //PS:所以如果想用拦截器做什么事情,可以拦截executor或者statementHandler的方法。
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
}

//PreparedStatementHandler的构造方法直接调用了父类BaseStatementHandler的构造方法:
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
      //insert操作传过来的boundSql为null,肯定会走到这里。
      //先生成key
      generateKeys(parameterObject);
      //获取boundSql
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;

    //简单的封装,赋值
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}

//生成key的逻辑
protected void generateKeys(Object parameter) {
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    ErrorContext.instance().store();
    keyGenerator.processBefore(executor, mappedStatement, null, parameter);
    ErrorContext.instance().recall();
}

//看一下SelectKeyGenerator是怎么做的
public class SelectKeyGenerator implements KeyGenerator {
  public static final String SELECT_KEY_SUFFIX = "!selectKey";
  private boolean executeBefore;
  private MappedStatement keyStatement;

  public SelectKeyGenerator(MappedStatement keyStatement, boolean executeBefore) {
    this.executeBefore = executeBefore;
    this.keyStatement = keyStatement;
  }

  public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    //如果是在执行前生成key
    if (executeBefore) {
      processGeneratedKeys(executor, ms, parameter);
    }
  }

  public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
    if (!executeBefore) {
      processGeneratedKeys(executor, ms, parameter);
    }
  }

  private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
    try {
      final Configuration configuration = ms.getConfiguration();
      if (parameter != null) {
        String keyStatementName = ms.getId() + SELECT_KEY_SUFFIX;
        if (configuration.hasStatement(keyStatementName)) {

          if (keyStatement != null && keyStatement.getKeyProperties() != null) {
            String keyProperty = keyStatement.getKeyProperties()[0]; //just one key property is supported
            //MetaObject是一个工具类,可以获取封装的对象的属性的值或者设置属性的值
            //获取设置的key对应的属性,以及查看parameter是否能够为该属性设置值
            final MetaObject metaParam = configuration.newMetaObject(parameter);
            if (keyProperty != null && metaParam.hasSetter(keyProperty)) {
              // Do not close keyExecutor.
              // The transaction will be closed by parent executor.
              //此处执行一次查询操作,查询操作执行过程在其他文章中再说,这里先简单理解为执行一次查询操作获取到key就好了。
              Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
              List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
              if (values.size() > 1) {
                throw new ExecutorException("Select statement for SelectKeyGenerator returned more than one value.");
              }
              metaParam.setValue(keyProperty, values.get(0));
            }
          }
        }
      }
    } catch (Exception e) {
      throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
    }
  }

}

//再看是如何获取BoundSql的
public final class MappedStatement {
  public BoundSql getBoundSql(Object parameterObject) {
    //此处的sqlSource是DynamicSqlSource
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

    //如果parameterMappings为空或者size <= 0,发生这种状况的话,个人理解是,sql语句中没有变量或者所有的变量都是${}这样表示的
    if (parameterMappings == null || parameterMappings.size() <= 0) {
        //此时boundSql的parameterMappings取值为parameterMap.getParameterMappings。
      boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
    }

    // check for nested result maps in parameter mappings (issue #30)
    for (ParameterMapping pm : boundSql.getParameterMappings()) {
      String rmId = pm.getResultMapId();
      if (rmId != null) {
        ResultMap rm = configuration.getResultMap(rmId);
        if (rm != null) {
          hasNestedResultMaps |= rm.hasNestedResultMaps();
        }
      }
    }

    return boundSql;
  }
}

//SqlSource获取BoundSql的逻辑
public class DynamicSqlSource implements SqlSource {
  public BoundSql getBoundSql(Object parameterObject) {
    //此处相当于对parameterObject做了一层封装。
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    //sqlNode应用context,这里也处理了动态sql语句中<if>, <foreach>这些情况。
    //处理一些表达式的时候用到了OGNL
    //另外,${}这样表示的变量,在这里被变量的具体value替换了。
    rootSqlNode.apply(context);

    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    //根据sql语句生成SqlSource对象
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    //获取boundSql,sqlSource.getBoundSql方法中new了一个BoundSql,其构造方法也只是做了简单的赋值。
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);

    //这个地方相当于是说把parameterObject对象里,参数和值的对应关系保存在additionalParameter中。
    for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
      boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
    }
    return boundSql;
  }
}

public class SqlSourceBuilder extends BaseBuilder {
  public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
    ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
    GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
    //此处得到完成的sql语句,#{}这样表示的变量,会被"?"替换,具体对应的参数名字被放在handler.parameterMappings中
    String sql = parser.parse(originalSql);
    return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
  }
}

至此,获取statementHandler的逻辑结束。

再看一眼SimpleExecutor.doUpdate做的事情

public class SimpleExecutor extends BaseExecutor {
  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);

      //接下来看看这一部分逻辑,获取Statement。
      stmt = prepareStatement(handler, ms.getStatementLog());

      //执行具体的update操作。
      return handler.update(stmt);
    } finally {
        //关闭Statement
      closeStatement(stmt);
    }
  }

  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    //这部分代码是不是看起来就有点眼熟的赶脚!
    //从transaction中获取connection,如果log是debug级别,会为connection生成一个能够打印比较多log的代理。
    Connection connection = getConnection(statementLog);
    //handler为RoutingStatementHandler,它作为PreparedStatementHandler的代理。
    //初始化statement
    stmt = handler.prepare(connection);
    //设置参数
    handler.parameterize(stmt);
    return stmt;
  }
}

//初始化statement的过程
public class PreparedStatementHandler extends BaseStatementHandler {

    //prepare方法继承的是父类BaseStatementHandler的
  public Statement prepare(Connection connection) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      //初始化prepareStatement
      statement = instantiateStatement(connection);
      //设置语句超时时间,如果该条语句设置的超时时间为空,则从configuration获取。
      setStatementTimeout(statement);
      //设置语句每次返回结果条数,如果为空则忽略。
      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);
    }
  }

  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);
    }
  }

  public void parameterize(Statement statement) throws SQLException {
    parameterHandler.setParameters((PreparedStatement) statement);
  }
}

//DefaultParameterHandler.setParameters
public void setParameters(PreparedStatement ps) throws SQLException {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    //parameterMappings中保存着动态sql中每个参数的名字,additionalParameter中保存着参数对应的值。
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
      MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);
      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 {
            value = metaObject == null ? null : metaObject.getValue(propertyName);
          }
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          if (typeHandler == null) {
            throw new ExecutorException("There was no TypeHandler found for parameter " + propertyName + " of statement " + mappedStatement.getId());
          }
          JdbcType jdbcType = parameterMapping.getJdbcType();
          if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
          //真正为PrepareStatement设置参数的地方。
          typeHandler.setParameter(ps, i + 1, value, jdbcType);
        }
      }
    }
  }

上面是获取statement的过程,下面就要具体执行update操作了,在PrepareStatementHandler中:

public class PreparedStatementHandler extends BaseStatementHandler {

  public int update(Statement statement) throws SQLException {
    //这几句都很熟
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    int rows = ps.getUpdateCount();

    //这里同样是获取key的逻辑
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    //如果keySelect语句设置的是在sql执行之后在执行,那么此处去或得下一个key。(具体逻辑和之前的一样)
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    //返回影响的条数。
    return rows;
  }
}

至此,插入操作执行结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值