mybatis 参数绑定(Mybatis参数-ParameterHandler设置参数)
Mybatis中SqlSession执行Sql语句过程中,实际上是通过Executor来执行Sql
Executor执行Sql的方法中,又是通过StatementHandler来实现
Executor中首先会创建StatementHandler对象,如果创建的是PrepareStatementHandler和CallableStatementHandler,在创建了对应的Statement之后,会使用ParemeterHandler给Statement设置参数
2.configuration中创建ParameterMapping
首先看下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设置参数
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com