Mybatis学习系列(八):Insert,update,delete的执行

本文详细解析了Mybatis中Insert、update、delete操作的执行过程,包括通过MapperMethod获取MappedStatement,处理集合参数,执行executor的update方法,重点介绍了SimpleExecutor的执行步骤,如获取数据库连接、预编译Statement、设置参数信息,以及最终执行update方法。通过这些步骤,全面了解Mybatis的 CRUD 操作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于MapperMethod中Insert,update,delete这三个的执行方式是一样的,我们统一看一下

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

这里都是两步,①执行sqlsession的对应方法②对执行结果进行处理

1.执行sqlsession的对应方法:最终都是走的update方法

public int insert(String statement) {
    return insert(statement, null);
  }

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

  @Override
  public int update(String statement) {
    return update(statement, null);
  }

  @Override
  public int delete(String statement) {
    return update(statement, null);
  }

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


  @Override
  public int update(String statement, Object parameter) {
    try {
      dirty = true;
      //1.根据ID获取MappedStatement
      MappedStatement ms = configuration.getMappedStatement(statement);
      //2.对集合参数进行处理
      //3.执行executor的update方法
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

1.1根据ID获取MappedStatement 对象:缓存中获取

public MappedStatement getMappedStatement(String id) {
    return this.getMappedStatement(id, true);
  }

  public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
    if (validateIncompleteStatements) {
      buildAllStatements();
    }
    return mappedStatements.get(id);
  }

1.2对集合参数进行处理

private Object wrapCollection(final Object object) {
    //如果是集合类型的参数
    if (object instanceof Collection) {
      //参数以,map形式返回
      StrictMap<Object> map = new StrictMap<Object>();
      //设置参数名称为collection
      map.put("collection", object);
      //如果是list类型
      if (object instanceof List) {
        //设置参数名称为list
        map.put("list", object);
      }
      return map;
    } else if (object != null && object.getClass().isArray()) {
      //如果是数组类型,以map形式返回
      //设置参数名称为array
      StrictMap<Object> map = new StrictMap<Object>();
      map.put("array", object);
      return map;
    }
    //不是集合和数组类型  原样返回
    return object;
  }

1.3执行executor(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.");
    }
    clearLocalCache();
    return doUpdate(ms, parameter);
  }

默认情况我们都是走的SimpleExecutor,我们看一下这里的update方法实现

 public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      //1.获取配置类
      Configuration configuration = ms.getConfiguration();
      //2.获取StatementHandler 执行器
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      //3.获取Statement
      stmt = prepareStatement(handler, ms.getStatementLog());
      //4.StatementHandler 执行 update方法
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }

1.3.1获取配置类:ms.getConfiguration(),直接获取MappedStatement 中的Configuration变量

1.3.2获取StatementHandler 执行器

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    //1.根据mappedStatement的Statementtype获取对应的StatementHandler
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    //2.在StatementHandler上添加插件拦截器
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

上图是StatementHandler 的实现关系图:我们看一下如何生成需要的真实对象的(是在RoutingStatementHandler初始化的时候完成的),一般情况我们都是预编译的StatementHandler(PreparedStatementHandler)

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

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

  }

1.3.3获取Statement:调用SimpleExecutor的prepareStatement方法

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    //1.获取数据库连接
    Connection connection = getConnection(statementLog);
    //2.调用StatementHandler生成Statement 
    stmt = handler.prepare(connection, transaction.getTimeout());
    //3.设置参数信息
    handler.parameterize(stmt);
    return stmt;
  }

1.3.3.1获取数据库连接:transaction --> dataSource

protected Connection getConnection(Log statementLog) throws SQLException {
    //通过transaction事务里面的配置获取数据库连接
    Connection connection = transaction.getConnection();
    if (statementLog.isDebugEnabled()) {
      //如果开启了日志debug模式 生成一个带有日志的连接
      return ConnectionLogger.newInstance(connection, statementLog, queryStack);
    } else {
      return connection;
    }
  }

public Connection getConnection() throws SQLException {
    if (connection == null) {
      openConnection();
    }
    return connection;
  }

protected void openConnection() throws SQLException {
    if (log.isDebugEnabled()) {
      log.debug("Opening JDBC Connection");
    }
    //调用的是dataSource的方法
    connection = dataSource.getConnection();
    if (level != null) {
      connection.setTransactionIsolation(level.getLevel());
    }
    setDesiredAutoCommit(autoCommmit);
  }

1.3.3.2调用StatementHandler生成Statement

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      //根据数据库连接 初始化Statement
      statement = instantiateStatement(connection);
      //设置Statement的超时时间
      setStatementTimeout(statement, transactionTimeout);
      //设置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);
    }
  }

//根据数据库连接 初始化Statement  最终都是通过Connection 去获取的Statement
protected Statement instantiateStatement(Connection connection) throws SQLException {
    //获取执行的sql
    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);
    }
  }

1.3.3.3设置参数信息

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

这里调用的还是parameterHandler的方法,我们看一下parameterHandler是如何生成的:在初始化StatementHandler的时候,在构造方法中初始化了parameterHandler

this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    //1.生成ParameterHandler 
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
    //添加相应的插件拦截器链
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
  }

//1.生成ParameterHandler == DefaultParameterHandler
public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
  }

下面就是设置参数了

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

//设置参数的值 其实就是设置给PreparedStatement 
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
    if (parameter == null) {
      if (jdbcType == null) {
        throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
      }
      try {
        ps.setNull(i, jdbcType.TYPE_CODE);
      } catch (SQLException e) {
        throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
                "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
                "Cause: " + e, e);
      }
    } else {
      try {
        setNonNullParameter(ps, i, parameter, jdbcType);
      } catch (Exception e) {
        throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
                "Try setting a different JdbcType for this parameter or a different configuration property. " +
                "Cause: " + e, e);
      }
    }
  }

1.3.4StatementHandler (PreparedStatementHandler)执行 update方法

public int update(Statement statement) throws SQLException {
    //这接执行PreparedStatement 的execute方法操作数据库
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    //获取执行成功的条数
    int rows = ps.getUpdateCount();
    //处理selectKey的情况
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
  }

2.对执行结果进行处理

private Object rowCountResult(int rowCount) {
    final Object result;
    //方法返回是void
    if (method.returnsVoid()) {
      result = null;
    } else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
      //返回的是Integer类型
      result = rowCount;
    } else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
      //返回的是Long类型
      result = (long)rowCount;
    } else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
      //返回的是Boolean类型
      result = rowCount > 0;
    } else {
      //抛出异常,返回的格式不正确
      throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
    }
    return result;
  }

到这里Insert,update,delete的执行全过程就解析结束了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值