介紹
ParameterHandler是在SatementHandler執行prepared比如預編譯SQL後,設定參數時使用的類
接口
ParameterHandler也隻是一個接口
public interface ParameterHandler {
Object getParameterObject();
void setParameters(PreparedStatement ps)
throws SQLException;
}
說明:
- 隻有兩個方法:擷取參數和設定參數。
- 它隻有一個實作類DefaultParameterHandler.java
ParameterHandler的建立。
通過源碼調用分析,可以看到ParameterHandler是在StatementHandler對象建立時,一起建立的.
具體代碼如下:
BaseStatementHandler.java
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
...
## ParemeterHandler建立入口
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
## ResultHandler建立入口
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
Configuration.java
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
XMLLanguageDriver
@Override
public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
## 這裡建立 DefaultParameterHandler
return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
}
建立時 傳入三個對象:執行SQL對應的配置資訊MappedStatement、參數對象Object,SQL的BoundSql。
注:一個BoundSql對象,代表了一次sql語句的實際執行,而SqlSource對象的責任,就是根據傳入的參數對象,動态計算出這個BoundSql,也就是說Mapper檔案中的節點的計算,是由SqlSource對象完成的。SqlSource最常用的實作類是DynamicSqlSource
setParement
設定參數
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
## 1.擷取所有參數,ParameterMapping是java類型和jdbc類型的對應關系
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = ; 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);
}
//擷取參數值對應的jdbc類型
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
typeHandler.setParameter(ps, i + , 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);
}
}
}
}
}
parameterObject 參數,可以是MAP,一個實體對象,或者基本資料類型。
上面大緻流程是,根據參數清單,使用BaseTypeHandler來設定參數。BaseTypeHandler其底層調用的是java的PreparedStatement.setXXX 方法來設定參數。
調用時機說明:
setParameter方法是在Executor進行調用的。
以SimpleExecutor為例
@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);
}
}
## 擷取連接配接、預編譯prepare方法,設定參數都在該方法中執行
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;
}
參考
- Mybatis 之 ParameterHandler
- MappedStatement,SqlSource,BoundSql