1.StatementHandler中通过ParemeterHandler给Statement设置参数

Mybatis中SqlSession执行Sql语句过程中,实际上是通过Executor来执行Sql

Executor执行Sql的方法中,又是通过StatementHandler来实现

Executor中首先会创建StatementHandler对象,如果创建的是PrepareStatementHandler和CallableStatementHandler,在创建了对应的Statement之后,会使用ParemeterHandler给Statement设置参数

mybatis 参数绑定(Mybatis参数-ParameterHandler设置参数)(1)

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

3.ParameterHandler实例化

ParameterHandler是一个接口,其实现类是DefaultParameterHandler

mybatis 参数绑定(Mybatis参数-ParameterHandler设置参数)(2)

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

4.ParameterHandler给PrepareStatement传递参数

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

5.TypeHandler设置参数

这里简单看下StringTypeHandler的设置方法,StringTypeHandler继承BaseTypeHandler类

BaseTypeHandler类的setParameter方法中,如果只不为null,则会调用setNonNullParameter方法,StringTypeHandler中实现了该方法,方法中直接使用下标的方式给PrepareStatement设置String类型的参数

mybatis 参数绑定(Mybatis参数-ParameterHandler设置参数)(3)

public class StringTypeHandler extends BaseTypeHandler<String> { public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter); } ... }

6.总结

如果Mybatis中使用的是PrepareStatement,则会使用ParameterHandler给PrepareStatement设置参数,设置参数时,会根据MappedStatement的类型来选择对应的TypeHandler。在TypeHandler中直接通过下标方式给PrepareStatement设置参数

,