程序员

Mybatis|SqlSession四大对象(一)

2018-11-28  本文已影响0人  GGarrett

1. SqlSession四大对象之Executor

1.1 Executor简介

每一个SqlSession对象都被分配一个Executor,主要负责connection获取和statement对象管理方案。

1.2 Statement对象给管理方案
  1. 简单管理方案:一个Statement接口对象只执行一次。执行完毕就会Statement接口对象进行销毁。
  2. 可重用方案: 使用一个Map集合,关键字就是一条Sql语句。对应内容Statement接口对象,等到SqlSession再次接收到相同命令时,就从map集合找到对应Statement接口使用map.put("select * from order", Statement1)。
  3. 批处理管理方案:将多个Statement包含的SQL语句,交给一个Statement对象输送到数据库,形成批处理操作。
1.3 Executor继承结构
 @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);
  }
 private boolean hasStatementFor(String sql) {
    try {
      return statementMap.keySet().contains(sql) && !statementMap.get(sql).getConnection().isClosed();
    } catch (SQLException e) {
      return false;
    }
  }

  private Statement getStatement(String s) {
    return statementMap.get(s);
  }

  private void putStatement(String sql, Statement stmt) {
    statementMap.put(sql, stmt);
  }
@Override
  public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
    final Configuration configuration = ms.getConfiguration();
    final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
    final BoundSql boundSql = handler.getBoundSql();
    final String sql = boundSql.getSql();
    final Statement stmt;
    if (sql.equals(currentSql) && ms.equals(currentStatement)) {
      int last = statementList.size() - 1;
      stmt = statementList.get(last);
      applyTransactionTimeout(stmt);
     handler.parameterize(stmt);//fix Issues 322
      BatchResult batchResult = batchResultList.get(last);
      batchResult.addParameterObject(parameterObject);
    } else {
      Connection connection = getConnection(ms.getStatementLog());
      stmt = handler.prepare(connection, transaction.getTimeout());
      handler.parameterize(stmt);    //fix Issues 322
      currentSql = sql;
      currentStatement = ms;
      statementList.add(stmt); //
      batchResultList.add(new BatchResult(ms, sql, parameterObject));
    }
 @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);
    }
  }
1.4 Executor对象的创建

执行器对象由Coniguration对象负责创建(SqlSessionFactory),Coniguration对象会根据得到【ExecutorType】创建对应的Excecutor对象,并把这个Excecutor对象传给SqlSession对象。

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      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();
    }
  }

继续往newExecutor里面看一下,会根据选择器的类型来配合cacheEnabled来配合使用。

 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);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    //这个是代理对象   这个是给开发人员做插件开发用的
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }
1.5 ExcecutorType选择

ExecutorType来决定Configuration对象创建何种类型的执行器。它的赋值可以通过两个地方进行赋值:

<settings>
    <setting name="cacheEnabled" value="false"/>
  <!--  <setting name="defaultExcutorType" value="SIMPLE"/> -->
  <!-- <setting name="defaultExcutorType" value="REUSE"/> -->
    <setting name="defaultExcutorType" value="BATCH"/>
</settings>
 @Before
     public void start() throws IOException{
            InputStream is = Resources.getResourceAsStream("myBatis-config.xml");
            SqlSessionFactoryBuilder builderObj = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builderObj.build(is);
            factory.openSession(ExecutorType.BATCH);
            session = factory.openSession();
     }

2. SqlSession四大对象之StatementHandler

2.1 StatementHandler介绍

是四大神器中最重要的一个对象,负责操作Statement与数据库进行交流。在工作时还会使用ParameterHandler进行参数配置,使用ResultHandler将查询结果与实体类对象进行绑定。

在StatementHandler接口中有四种重要 方法,分别是:

//创建Statement对象或则PreparedStatment或则CallableStatment
Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;
  //主要针对PreparedStatment或则CallableStatment关联预编译SQL语句中占位符进行修改
  void parameterize(Statement statement)
      throws SQLException;
  //用于通知Statement将[insert,update,delete]推送到数据库
  int update(Statement statement)
      throws SQLException;
  //用于通知Statement将[select]推送到数据库并返回对应查询结果
  <E> List<E> query(Statement statement, ResultHandler resultHandler)
      throws SQLException;
2.2 StatementHandler继承结构
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());
    }

  }

BaseStatementHandler:是个抽象类,用于简化StatementHandler接口开发的难度,是适配器模式的体现,他有三个实现类:SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler。在RoutingStatementHandler创建时,就根据接受的Excutor来创建这三个类型对象。

2.3 StatementHandler对象的创建

StatementHandler对象是在SqlSession对象接收到操作命令时,由Configuraion中newStatementHandler方法负责调用的。

RoutingStatementHandler构造方法,将会根据Executor的类型决定创建SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler实例对象。

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());
    }
  }
2.3 StatementHandler接口介绍
@Override
  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);
    }
  }

  1. prepare方法:
 @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    if (mappedStatement.getResultSetType() != null) {
      return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.createStatement();
    }
  }

CallableStatementHandler

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

CallableStatementHandler

  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getResultSetType() != null) {
      return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.prepareCall(sql);
    }
  }
  1. parameterize方法
    主要为PreparedStatement和CallableStatement传参,因此只在这两个对象中被重写。
    PreparedStatementHandler中的parameterize。
 @Override
  public void parameterize(Statement statement) throws SQLException {
    parameterHandler.setParameters((PreparedStatement) statement);
  }

CallableStatementHandler中的parameterize.

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

在这两个方法中,可以看到都是ParameterHandler对象进行参数传参的。

  1. query方法
    输送查询语句,并将查询语句结果转换成对应的实体类。
    SimpleStatementHandler 中的 query 方法。
 @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();
    statement.execute(sql);
    return resultSetHandler.<E>handleResultSets(statement);
  }

PreparedStatementHandler中的query方法

@Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.<E> handleResultSets(ps);
  }

CallableStatementHandler中的query方法

 @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    CallableStatement cs = (CallableStatement) statement;
    cs.execute();
    List<E> resultList = resultSetHandler.<E>handleResultSets(cs);
    resultSetHandler.handleOutputParameters(cs);
    return resultList;
  }

可以看到在得到查询结果后,都是使用ResultSetHandler对结果进行转换.

  1. update方法
    输送insert、update、delete语句并返回处理数据行
    SimpleStatementHandler中的update方法
 @Override
  public int update(Statement statement) throws SQLException {
    String sql = boundSql.getSql();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    int rows;
    if (keyGenerator instanceof Jdbc3KeyGenerator) {
      statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
      rows = statement.getUpdateCount();
      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    } else if (keyGenerator instanceof SelectKeyGenerator) {
      statement.execute(sql);
      rows = statement.getUpdateCount();
      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    } else {
      statement.execute(sql);
      rows = statement.getUpdateCount();
    }
    return rows;
  }

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

CallableStatementHandler中update方法

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

2.4 关于三种数据库操作对象选择(不需要人为控制)

执行相关SQL语句:
情况1: select * from order; SimpleStatementHander Statement
情况2: select * from order where orderId=? PreparedStatementHandler PreparedStatement
情况3: call{pro} CallableStatementHandler CallableStatment

上一篇下一篇

猜你喜欢

热点阅读