blog

Mybatisのソースコード(V) --- sqlSessionの4つの主要なオブジェクト

Javaとデータベースの間のやりとりを実際に行うのは、実際に作業を行うオブジェクトであるエクゼキュータです。 updateまたはselectのすべての実行は、ステートメントオブジェクトを開き、すぐにス...

Jan 11, 2021 · 20 min. read
シェア

Executor

これはエクゼキュータであり、javaがデータベースとやりとりする実際の作業を行うオブジェクトです。

public interface Executor {
 ResultHandler NO_RESULT_HANDLER = null;
 int update(MappedStatement ms, Object parameter) throws SQLException;
 <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
 <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
 <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
 List<BatchResult> 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);
}

メソッド名とパラメータを見れば、それぞれのメソッドの役割がわかるでしょう。

エクゼキュータの分類

エクゼキュータは2つのカテゴリに分けられます:

  • ベースエクゼキュータ

    • ReuseExecutor:ステートメントオブジェクト、使用の存在を見つけるためにキーとして更新または選択、SQLを実行すると、作成時に存在しない、ステートメントオブジェクトの使用後に閉じていないが、次の使用のためにマップに配置されます。
    • BatchExecutor:更新を実行し、すべてのSQLをバッチに追加し、統一された実行を待って、それは複数のステートメントオブジェクトをキャッシュし、各ステートメントオブジェクトは、バッチごとにexecuteBatch()バッチの実行を待って、addBatch()終了です。バケツの数を維持することに相当し、各バケツは、独自のSQLの多くで満たされている、ちょうどリンゴの青はリンゴの多くで満たされ、トマトの青はトマトの多くで満たされ、最後に、倉庫に注ぐように。
  • CachingExecutor

エクゼキュータの作成

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

ExecutorType execType はデフォルト値の存在で、コンフィギュレーションではデフォルトで定義されています。

ExecutorType は列挙型で、そのデータを見るためのポイントです。
public enum ExecutorType {
 SIMPLE, REUSE, BATCH
}

SimpleExecutor、ReuseExecutor、BatchExecutor クラスの BaseExecutor は、リターン・メソッドに対応します。

final Executor executor = configuration.newExecutor(tx, execType);

newExecutor へ

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

簡単な判定の後、あなたは最後の戻りSimpleExecutorオブジェクトを知ることができます。

エクゼキュータの実行

SQLの理解のsqlSessionの実行の原則を通じて、Executorの使用は、SQLステートメントの特定の使用であることを知って、ここでselectListメソッドを置くためにExecutorのメソッドを使用して起動します。

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
 try {
 MappedStatement ms = configuration.getMappedStatement(statement);
 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
 } catch (Exception e) {
 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
 } finally {
 ErrorContext.instance().reset();
 }
 }

executor.queryメソッドに

public <E> List<E> 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);
 }

doQueryメソッドのSimpleExecutorオブジェクトの作成を入力するまで、クエリメソッドを入力し続けます。

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

そうです!これで2番目のキーオブジェクトであるStatementHandlerが現れました。

ステートメントハンドラ

これは、MybatisとJDBC Statement、JDBC Statementの間のインタラクションを処理する役割を担っており、JDBC Statementは、JDBCの研究において、時間の理解において、データベース・オブジェクトとのインタラクションを担っており、エクゼキュータも、同じように、作成されたコンフィギュレーションによるものです!

public interface StatementHandler {
 Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
 void parameterize(Statement statement) throws SQLException;
 void batch(Statement statement) throws SQLException;
 int update(Statement statement) throws SQLException;
 <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
 <E> Cursor<E> queryCursor(Statement statement) throws SQLException;
 BoundSql getBoundSql();
 ParameterHandler getParameterHandler();

StatementHandler

およそ4つのStatementHandlerインターフェイスの実装では、そのうちの3つのクラスと対応するJDBCステートメントを実装します。

  • SimpleStatementHandlerは、これは非常に単純な、対応するJDBC一般的に使用されるステートメントインターフェイスは、単純なSQL処理のためです;
  • RoutingStatementHandlerは、このインターフェイスは、上記の3つのインターフェイスのルートは、実際の操作はありませんが、上記の3つのStatementHandlerの作成と呼び出しを担当しています。

StatementHandler

doQueryメソッドのコードに戻る

StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

wrapperはエクゼキュータです msは要するに、xmlで設定された名前空間のidの内容です パラメータは入力値です rowBoundsはページングのresultHandlerなどです boundSqlはSQL文の実際の呼び出しと対応するパラメータ関連オブジェクトです

newStatementHandler メソッドを入力します。

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;
 }
  • このインターフェイスは、上記の3つのインターフェイスのルーティングは、実際の操作はありませんが、唯一の作成と上記の3つのStatementHandlerの呼び出しを担当

メソッドにnew RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql)を追加します;

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

分析によると、msはMappedStatementオブジェクトですこれは、StatementHandlerの実装を決定するStatementTypeの型によると、およびRoutingStatementHandlerは、デリゲートオブジェクトを介して、デリゲートオブジェクトを維持することは明らかです。実際のHandlerオブジェクトの呼び出しを達成するためにデリゲートオブジェクトを介して。実際には、作成、およびExecutorで私たちのStatementTypeは、同じ、デフォルトで設定されていた、ちょっと、ちょっと、ちょっと、デフォルトはPREPAREDです。

MappedStatement

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
 try {
 MappedStatement ms = configuration.getMappedStatement(statement);
 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
 } catch (Exception e) {
 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
 } finally {
 ErrorContext.instance().reset();
 }
 }

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

validateIncompleteStatements、trueを渡し、掘り続けます。

 if (!incompleteResultMaps.isEmpty()) {
 synchronized (incompleteResultMaps) {
 // This always throws a BuilderException.
 incompleteResultMaps.iterator().next().resolve();
 }
 }
 if (!incompleteCacheRefs.isEmpty()) {
 synchronized (incompleteCacheRefs) {
 // This always throws a BuilderException.
 incompleteCacheRefs.iterator().next().resolveCacheRef();
 }
 }
 if (!incompleteStatements.isEmpty()) {
 synchronized (incompleteStatements) {
 // This always throws a BuilderException.
 incompleteStatements.iterator().next().parseStatementNode();
 }
 }
 if (!incompleteMethods.isEmpty()) {
 synchronized (incompleteMethods) {
 // This always throws a BuilderException.
 incompleteMethods.iterator().next().resolve();
 }
 }
 }
MappedStatement.Builder statementBuilder = new MappedStatement.Builder

上記のコードが見つかりました。

StatementTypeも列挙型であることがわかります。
public enum StatementType {
 STATEMENT, PREPARED, CALLABLE
}

さて、StatementHandlerオブジェクトができたので、doQueryメソッドに戻ってください。

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

次のメソッドに進みます。

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

handler.prepareメソッドに進みます。

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

ステートメントがPreparedStatementであることを知っているので、直接PreparedStatementHandlerクラスの実装を見ると、コードはあまりありませんが、入力し続けます。

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

あまり言うことは、Connectionメソッドを介してステートメントのインスタンスオブジェクトを取得することです、これまでのところ、StatementHandlerオブジェクトの良い特定の実装の作成 今すぐprepareStatementメソッドに戻る

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

handler.parameterize(stmt);メソッドに戻ります。

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

3番目のオブジェクトは、parameterHandler登場

パラメータハンドラー

parameterHandler は

public interface ParameterHandler {
 Object getParameterObject();
 void setParameters(PreparedStatement ps)
 throws SQLException;
}

推測するのは難しくありません。その2つのメソッドは、入力パラメータの取得と入力パラメータの設定です。 DefaultParameterHandlerクラスの実装は1つだけです。

DefaultParameterHandler

私たちは主にそのsetメソッドを見て、parameterizeメソッドは、呼び出しがsetParametersメソッドであるため

 public void setParameters(PreparedStatement ps) throws SQLException {
 ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
 // parameterMappings  #{} このブログで与えられたパラメータ情報のカプセル化、つまり、パラメータ化されたSQLであればこのSQLは存在することになるが、パラメータ化されたSQLではない。
 List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
 //パラメータ化されたSQLなら、パラメータを設定しなければならない
 if (parameterMappings != null) {
 for (int i = 0; i < parameterMappings.size(); i++) {
 ParameterMapping parameterMapping = parameterMappings.get(i);
 //パラメータの型がOUT型でない場合、CallableStatementHandlerは
 //出力パラメータはストアドプロシージャにしか存在しないので、パラメータが出力パラメータでないときは
 if (parameterMapping.getMode() != ParameterMode.OUT) {
 Object value;
 //このクエリでは、対応するのはBeanではなく、additionalParameters Mapオブジェクトに対応するので、ここでのプロパティはBeanのプロパティではなく、カプセル化されたKeyである。
 //ビーンであれば、プロパティのリフレクションを通じて値を取得する
 String propertyName = parameterMapping.getProperty();
 //propertyNameがadditionalParametersのキーである場合
 if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
 //キーでマップの値を取得する
 value = boundSql.getAdditionalParameter(propertyName);
 }//additionalParametersのKeyでなく、入力パラメータがNULLの場合、値はNULLになる
 else if (parameterObject == null) {
 value = null;
 } 
 //typeHandlerRegistryがClassオブジェクトのパラメータに登録されている場合、つまり、彼はPrimitive型または文字列ByteArrayなど26型、つまり、JavaBeanはMapリスト型ではない。
 else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
 value = parameterObject;
 }
 //それ以外の場合は、Map型またはBeanのカプセル化されたMataObjectオブジェクトを介して、propertyNameで、対応する値を取得するには、Beanの反射を介して取得するには、Map型は、キーを介して値を取得することである。
 else {
 MetaObject metaObject = configuration.newMetaObject(parameterObject);
 value = metaObject.getValue(propertyName);
 }
 //SqlSourceのparseメソッドを通してparamterMappingsを取得する具体的な実装では、parameterMappingのTypeHandlerを取得する。
 //このクエリのTypeHandlerはIntegerTypeHandlerである
 TypeHandler typeHandler = parameterMapping.getTypeHandler();
 //対応する parameterMapping の JdbcType を取得する。#{}で明示的に指定されている場合、jdbcTypeはnullである。
 JdbcType jdbcType = parameterMapping.getJdbcType();
 //値が NULL で、jdbcType も NULL の場合、jdbcType が構成になる。.getJdbcTypeForNull(); つまり、OTHERなので、マッパープロファイルのInsertやUpdateタイプのSqlMapperを書くときに、もしある#{propertyName}対応するValueがNullの場合、データベースへの挿入はエラーを報告する。
// この時点でjdbcTypeがOtherであるため、setNullの実行は、エラーを報告する
 //java.sql.SQLException: 無効な列型: 1111 
 //1111 それは他の対応するsqlTypeである
 // つまり、Valueをnullとして、jdbcTypeを指定する必要がある。
 if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
 //この行は、特定のpsを実装する.set***
 typeHandler.setParameter(ps, i + 1, value, jdbcType);
 }
 }
 }
 }
次にtypeHandler.setParameterメソッドを入力します。
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);
 }
 }
 }

ケースのほとんどは、直接抽象的なメソッドであるsetNonNullParameterに、NULLを決定することです、サブクラスの特定の実装では、ここで特定の達成するためにサブクラスにブレークポイントを作成します。

 public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
 throws SQLException {
 ps.setInt(i, parameter);
 }

非常に単純な、PreparedStatementの特定のメソッドは、つまり、ですか?割り当てここでは、割り当て操作は、SimpleExecutor doQueryメソッドに戻り続ける完了です。

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

stmtの値を確認するためのブレークポイント。

次のメソッド、handler.query()に進みます。
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
 PreparedStatement ps = (PreparedStatement) statement;
 ps.execute();
 return resultSetHandler.<E> handleResultSets(ps);
 }

さて、3つ目のオブジェクト、サイレントresultSetHandlerが動き出します。

ResultSetHandler

は、データベースの結果セットをJavaオブジェクトのコレクションに変換する役割を果たします。

public interface ResultSetHandler {
 <E> List<E> handleResultSets(Statement stmt) throws SQLException;
 <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
 void handleOutputParameters(CallableStatement cs) throws SQLException;
}

メソッドによると判断するのは難しいことではありません、最初のメソッドは、結果コレクションのリストに戻ることです、2番目はCursorオブジェクトにカプセル化されています。

ResultSetHandler

実際には、それは唯一の実装クラスDefaultResultSetHandlerを持っています。

handleResultSets は、データベースの結果セットを処理する中核となるメソッドです。DefaultResultSetHandlerはResultSetHandler結果の唯一の実装クラスは、結果セットの処理は基本的にすべてResultSetHandlerの内部です。ResultSetHandlerは、処理プロセスの結果セットを見て、プロセスの詳細は非常に多くのため、あなたは、ネストなど、さまざまな構成を考慮する必要があるので、プロセスを組み合わせることで、全体の主流のプロセスを把握することを目的とし、あまりにも多くのコードの各行を解析することはありません。

ハンドル結果セット

具体的なコードです。

/**
 * StatementHandler内のqueryメソッドから呼び出される、結果セットを処理するメソッド
 * PSこのメソッドは、ステートメント、プリペアドステートメント、ストアドプロシージャの CallableStatement が返す結果セットを扱うことができる。また、CallableStatementは複数の結び目を返すことができる。
 * 果物のセットは、通常のクエリは、一般的に単一の結果セットである
 * */
 @Override
 public List<Object> handleResultSets(Statement stmt) throws SQLException {
 ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
 //1.結果セットオブジェクトを保存する。通常のクエリでは、ResultSetは実際には1つだけで、つまりmultipleResultsは最大でも1つの要素しか持たない。multipleResultSetの場合
 //ResultSetは一般的にストアドプロシージャに表示され、各ResultSetがObjectオブジェクトに対応する場合、各Objectはリストである<Object> 
 final List<Object> multipleResults = new ArrayList<Object>();
 int resultSetCount = 0;
 //2.StatementResultSetWrapperオブジェクトにカプセル化された複数の結果セットオブジェクトを返すかもしれない、最初に最初の結果セットを扱う
 ResultSetWrapper rsw = getFirstResultSet(stmt);
 //3.結果セットは、変換ルールを知っている必要が変換され、レコードとJavaBeanの変換ルールはresultMapの内側にあり、ここでresultMapを取得するには、取得に注意を払う
 //はすべてresultMapであり、これはリストであるが、通常のクエリでは、resultMapは1つの要素しか持っていない
 List<ResultMap> resultMaps = mappedStatement.getResultMaps();
 int resultMapCount = resultMaps.size();
 //4.結果セットと変換ルールが空であってはならない、さもなければ例外が投げられる
 validateResultMapsCount(rsw, resultMapCount);
 //5.一つ一つの処理
 while (rsw != null && resultMapCount > resultSetCount) {
 //6.現在の結果セットに対応するresultMapを取得する
 ResultMap resultMap = resultMaps.get(resultSetCount);
 //7.ルールに従ってResultSetを処理し、ResultSetをオブジェクトリストに変換し、multipleResultsに保存する
 //これは、結果セットを取得するための最もコアなメソッドのステップである
 handleResultSet(rsw, resultMap, multipleResults, null);
 //8.次の結果セットを取得する
 rsw = getNextResultSet(stmt);
 //9.nestedResultObjectsオブジェクトをクリアする
 cleanUpAfterHandlingResultSet();
 resultSetCount++;
 }
 //10.複数の結果セットを取得する。一般的にストアドプロシージャに表示され、分析しない...
 String[] resultSets = mappedStatement.getResultSets();
 if (resultSets != null) {
 while (rsw != null && resultSetCount < resultSets.length) {
 ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
 if (parentMapping != null) {
 String nestedResultMapId = parentMapping.getNestedResultMapId();
 ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
 handleResultSet(rsw, resultMap, null, parentMapping);
 }
 rsw = getNextResultSet(stmt);
 cleanUpAfterHandlingResultSet();
 resultSetCount++;
 }
 }
 //11.それがmultipleResults 1つだけの要素である場合は、返すために最初の要素を取る
 return collapseSingleResultList(multipleResults);
 }

コアとなるコードは

handleResultSet(rsw, resultMap, multipleResults, null);

handleResultSet

ディスカバリー・コードへ

 private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
 try {
 //1.ストアドプロシージャでない場合、parentMappingはnullである。handleResultSetsメソッドの最初のwhileループは、パラメータがnullであることを渡す。
 if (parentMapping != null) {
 handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
 } else {
 //1.2カスタムresultHandlerがない場合は、デフォルトのDefaultResultHandlerオブジェクトを使用する
 if (resultHandler == null) {
 //1.3DefaultResultHandlerオブジェクトを作成する
 DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
 //1.4(ResultSet Rowによって返された各行を処理するためのCoreメソッド)は、結果セット全体をループする
 handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
 //1.5defaultResultHandlerの処理結果をmultipleResultsに追加する
 multipleResults.add(defaultResultHandler.getResultList());
 } else {
 //1.6  .4同じように、各行を処理し、内部はすべての結果セットを循環する
 handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
 }
 }
 } finally {
 // issue #228 (close resultsets)
 //結果セット・オブジェクトを閉じる
 closeResultSet(rsw.getResultSet());
 }
 }

さらに下の行では、結果をオブジェクトの関係に1対1でマッピングしています。

要約

  • 内部的には、4つのオブジェクトの1つであるExecutorが呼び出され、実際の追加、削除、変更、取得を実行し、その後、入力されたパラメータを2回ラップする処理と、4つのオブジェクトの1つであるStatementHandlerを作成する処理です。
  • すぐに2番目のStatementHandlerの4つのオブジェクトの作成後、StatementHandlerを介して、プリコンパイルの4つの主要な手順を実行するには、値を挿入し、SQLの実行は、結果をパッケージ化します。
  • そして、StatementHandlerのより特定することができます労働の分担を遂行するために、プリコンパイルのStatementHandlerの実装では、PrepareStatmentオブジェクトの作成に相当します。すぐに3番目のparameterHandlerの4つの主要なオブジェクトの使用後に仕事のパラメータを設定し、StatementHandler stm.execute();データベースにパラメータを設定します、4つのオブジェクトの最後の最後の使用。
  • 最後に4つのオブジェクトの最後の resultSetHandler オブジェクトを使用して、結果をカプセル化するマッピングプロセスの役割を完了します。
  • そして、型変換とパラメータ解析の作業を静かに行う奇妙な仕事の一部を持つハンドラ、彼はTypeHandler、parameterHandlerとresultSetHandlerパラメータ設定と処理結果は、その助けを必要としています。
    Executorは:Mybatisは、SQLステートメントを実行し始めた StatementHandlerは:処理SQLステートメントプリコンパイル、パラメータおよびその他の関連作業を設定します。データベース型とjavaBean型のマッピング

Mybatis ソースコード --- SqlSessionFactoryBuilder (コンフィギュレーションファイルの取得)

Mybatis のソースコード --- XML ファイルを読み込む parseConfiguration .

Mybatis のソース・コード --- sql クエリを完成させる SqlSession

Mybatis ソース・コード --- SqlSession による動的エージェントの完成

個人的な意見です。議論へようこそ、

Read next

vue 画像圧縮 + 複数画像のアップロード

機能:このコンポーネントは、複数の画像を同時にアップロードし、各画像を圧縮してからアップロードすることをサポートします。

Jan 11, 2021 · 10 min read