Mybatis中SqlSession執行Sql語句過程中,實際上是通過Executor來執行Sql
Executor執行Sql的方法中,又是通過StatementHandler來實現
Executor中首先會創建StatementHandler對象,如果創建的是PrepareStatementHandler和CallableStatementHandler,在創建了對應的Statement之後,會使用ParemeterHandler給Statement設置參數
首先看下ParameterHandler的初始化過程,ParameterHandler是StatementHandler的一個屬性,在構造方法中進行初始化
初始化方法是通過Configuration的newParameterHandler方法實現
public abstract class BaseStatementHandler implements StatementHandler {
protected final ParameterHandler parameterHandler;
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
...
this.parameterHandler = this.configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
}
...
}
Configuration的newParameterHandler方法中,通過mappedStatement來創建ParameterHandler對象
創建了StatementHandler對象後,會調用interceptorChain的pluginAll方法來處理StatementHandler對象,最後強轉為StatementHandler類型
InterceptorChain中保存了Interceptor的集合,如果配置了Interceptor,那麼Interceptor會對StatementHandler對象進行動态代理,擴展StatementHandler的方法
public class Configuration {
protected final Map<String, MappedStatement> mappedStatements;
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler)this.interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
...
}
MappedStatement的getLang方法返回LanguageDriver對象,然後調用LanguageDriver的createParameterHandler方法創建ParameterHandler
LanguageDriver的默認實現是XMLLanguageDriver,XMLLanguageDriver中創建了一個DefaultParameterHandler對象
public class XMLLanguageDriver implements LanguageDriver {
public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
}
...
}
ParameterHandler是一個接口,其實現類是DefaultParameterHandler
DefaultParameterHandler的構造方法中對其屬性進行賦值
public class DefaultParameterHandler implements ParameterHandler {
private final TypeHandlerRegistry typeHandlerRegistry;
private final MappedStatement mappedStatement;
private final Object parameterObject;
private final BoundSql boundSql;
private final Configuration configuration;
public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
this.mappedStatement = mappedStatement;
this.configuration = mappedStatement.getConfiguration();
this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
this.parameterObject = parameterObject;
this.boundSql = boundSql;
}
...
}
了解了ParameterHandler的初始化過程之後,繼續查看ParameterHandler給PrepareStatement設置參數過程
在setParameters方法中會遍曆ParameterMapping,并根據屬性名在ParameterMapping中獲得值和TypeHandler,然後通過TypeHandler來給PrepareStatement設置參數
public class DefaultParameterHandler implements ParameterHandler {
...
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(this.mappedStatement.getParameterMap().getId());
//從BoundSql中獲得參數映射
List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings();
if (parameterMappings != null) {
//遍曆parameterMappings
for(int i = 0; i < parameterMappings.size(); i) {
ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);
//ParameterMode類型不為OUT
if (parameterMapping.getMode() != ParameterMode.OUT) {
//根據名稱獲得參數值
String propertyName = parameterMapping.getProperty();
Object value;
if (this.boundSql.hasAdditionalParameter(propertyName)) {
value = this.boundSql.getAdditionalParameter(propertyName);
} else if (this.parameterObject == null) {
value = null;
} else if (this.typeHandlerRegistry.hasTypeHandler(this.parameterObject.getClass())) {
value = this.parameterObject;
} else {
MetaObject metaObject = this.configuration.newMetaObject(this.parameterObject);
value = metaObject.getValue(propertyName);
}
//parameterMapping獲取TypeHandler和JdbcType
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = this.configuration.getJdbcTypeForNull();
}
try {
//通過TypeHandler給PrepareStatement設置參數
typeHandler.setParameter(ps, i 1, value, jdbcType);
} catch (SQLException | TypeException var10) {
throw new TypeException("Could not set parameters for mapping: " parameterMapping ". Cause: " var10, var10);
}
}
}
}
}
}
這裡簡單看下StringTypeHandler的設置方法,StringTypeHandler繼承BaseTypeHandler類
BaseTypeHandler類的setParameter方法中,如果隻不為null,則會調用setNonNullParameter方法,StringTypeHandler中實現了該方法,方法中直接使用下标的方式給PrepareStatement設置String類型的參數
public class StringTypeHandler extends BaseTypeHandler<String> {
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
}
...
}
如果Mybatis中使用的是PrepareStatement,則會使用ParameterHandler給PrepareStatement設置參數,設置參數時,會根據MappedStatement的類型來選擇對應的TypeHandler。在TypeHandler中直接通過下标方式給PrepareStatement設置參數
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!