Mybaitsソースコード分析(8)StatementHandlerの詳細な説明
概要:StatementHandlerは、主にMyBatisとJDBC間のStatementの相互作用の処理を担当します。一般的に、Statementオブジェクトとデータベース間の相互作用の操作を担当します。実行プロセスは、主にパラメータバインディングと結果エンティティクラスバインディングをParameterHandlerとResultSetHandlerに依存しています。
1つ、クラス紹介
1.
StatementHandlerのクラスレベルStatementHandler:更新、クエリ、パラメータ化、準備などのメソッドを定義する最上位のインターフェイス。
BaseStatementHandler:基本的な実装。ParameterHandlerとResultSetHandlerの作成を担当します。
PreparedStatementHandler:プリペアドステートメントの実装、
SimpleStatementHandler:シンプルなステートメントの実装、
CallableStatementHandler:ストアドプロシージャの実装。
RoutingStatementHandler:呼び出す実際の実装メソッドのデリゲートとしてさまざまな実装を作成するための、さまざまなタイプに応じたルーティングパッケージ。
2.コンストラクタ
StatementHandlerのコンストラクタは、主に実際の実行に必要ないくつかのパラメータを渡し、パラメータ処理と結果プロセッサを作成します。
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) {
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
// 创建参数处理器
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 创建结果处理器
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
第二に、実行プロセス
1.SQLステートメントの実行とパラメーターの解析段階
1)メインライン方式
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 (会根据statement类型创建不同的StatementHandler)
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 预处理语句
stmt = prepareStatement(handler, ms.getStatementLog());
// StatementHandler的query
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
// 调用StatementHandler的prepare方法
stmt = handler.prepare(connection);
// 调用hanlder的parameterize方法
handler.parameterize(stmt);
return stmt;
}
2)StatementHandlerのメソッドを準備します
StatementHandlerのprepareメソッドはBaseStatementHandlerに実装され、instantiateStatementメソッドが呼び出されます
public Statement prepare(Connection connection) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
statement = instantiateStatement(connection);
setStatementTimeout(statement);
setFetchSize(statement);
return statement;
}
}
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) {
// 预编译sql传入不同的resultSet的类型 (遍历方向)
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else { // 预编译sql
return connection.prepareStatement(sql);
}
}
prepareメソッドは、実際にはconnection.prepareStatementのカプセル化を呼び出します
。3)StatementHandlerのparameterizeメソッド
public void parameterize(Statement statement) throws SQLException {
// 调用parameterHandler设置参数
parameterHandler.setParameters((PreparedStatement) statement);
}
public void setParameters(PreparedStatement ps) throws SQLException {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
// 遍历parameterMappings
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)) {
// 从Additional中取属性值
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 jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
// preparedStatement设置参数
typeHandler.setParameter(ps, i + 1, value, jdbcType);
}
}
}
}
4)パラメータを設定した後、戻り値の処理を行う必要があります。メインラインのプロセスハンドラから続行します。<E> query(stmt、resultHandler)。
PreparedStatementHandler 的实现。
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute(); // 强转成预编译语句,执行execute然后交由结果处理器处理结果。
return resultSetHandler.<E> handleResultSets(ps);
}
SimpleStatementHandler 的实现
public <E> List<E> query(Statement statement, ResultHandler resultHandler)throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql); //直接执行sql
return resultSetHandler.<E>handleResultSets(statement);
}
2.戻り値の処理段階
上記からわかるように、戻り値の処理は主にresultSetHandlerによって処理されます。
結果セット処理のプロセスはより複雑なので、フォローアップで個別に説明します!
終わり!