目录
概念职责类图源码ParameterHandler对象创建ParameterHandler解析参数总结概念
职责
ParameterHandler是用来设置参数规则的。StatementHandler中介绍到,其SimpleExecutor中调用prepare()方法之后,接下来StatementHandler就是使用parameterize来设置参数。以SampleExecutor为例,具体代码如下:
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;}@Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters((PreparedStatement) statement);}
类图
进入源码,该接口很简单,且只有一个默认实现类DefaultParameterHandler
public interface ParameterHandler {Object getParameterObject();void setParameters(PreparedStatement ps)throws SQLException;}
getParameterObject()用于读取参数;setParameter():用于对PreparedStatementHandler的参数赋值;
源码
ParameterHandler对象创建
对于ParameterHandler对象的创建过程,首先抛出结论:该对象是在创建StatementHandler对象的同时被创建完成。StatementHandler文章中我们谈论到其依赖ParameterHandler和ResultSetHandler,下面我们进入正题。
上面谈到了该对象在StatementHandler对象创建时被创建,所以我们从StatementHandler对象位置开始跟踪:
SimpleExecutor
@Overridepublic <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt = null;try {// 获取环境配置Configuration configuration = ms.getConfiguration();//Configuration中获取StatementHandler,跟进去StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);stmt = prepareStatement(handler, ms.getStatementLog());return handler.query(stmt, resultHandler);} finally {closeStatement(stmt);}}
Configuration
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {//创建StatementHandlerStatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);return statementHandler;}
跟进RoutingStatementHandler,我们以SimpleStatementHandler为例,其余*StatementHandler对象创建一样,调用其父类BaseStatementHandler构造方法,所以我们跟踪到其父类的构造方法中。
SimpleStatementHandler
public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);}
BaseStatementHandler
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) {// issue #435, get the key before calculating the statementgenerateKeys(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);}
从代码注释上,我们可以清晰看到parameterHandler 和resultSetHandler 对象的创建交给Configuration类操作;
从上面几步源码的跟踪:Configuration类依次完成了StatementHandler、parameterHandler 、resultSetHandler 对象的创建过程。
那么继续回归到Configuration中。
Configuration
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);return parameterHandler;}
ParameterHandler解析参数
上面完成了StatementHandler,ParameterHandler和ResultSetHandler对象的创建,基本工作已准备完成,下面继续回归到SimpleExecutor#prepareStatement()
@Overridepublic <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt = null;try {// 获取环境配置Configuration configuration = ms.getConfiguration();//Configuration中获取StatementHandlerStatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);//准备Statement对象stmt = prepareStatement(handler, ms.getStatementLog());return handler.query(stmt, resultHandler);} finally {closeStatement(stmt);}}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;}
PrepareStatementHandler
@Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters((PreparedStatement) statement);}
代码里看到是parameterHandler对象调用,上面我们了解到ParameterHandler接口仅有一个实现类即DefaultParameterHandler,因此Debug进去。
DefaultParameterHandler
@Overridepublic void setParameters(PreparedStatement ps) {ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());// parameterMappings 就是对 #{} 或者 ${} 里面参数的封装List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings != null) {// 如果是参数化的SQL,便需要循环取出并设置参数的值for (int i = 0; i < parameterMappings.size(); i++) {ParameterMapping parameterMapping = parameterMappings.get(i);// 如果参数类型不是 OUT ,这个类型与 CallableStatementHandler 有关// 因为存储过程不存在输出参数,所以参数不是输出参数的时候,就需要设置。if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;// 得到#{} 中的属性名String propertyName = parameterMapping.getProperty();// 如果 propertyName 是 Map 中的keyif (boundSql.hasAdditionalParameter(propertyName)) {// issue #448 ask first for additional params// 通过key 来得到 additionalParameter 中的value值value = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {// 如果不是 additionalParameters 中的key,而且传入参数是 null, 则value 就是nullvalue = null;}// 如果 typeHandlerRegistry 中已经注册了这个参数的 Class对象,即它是Primitive 或者是String 的话else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else {// 否则就是 MapMetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}// 在通过SqlSource 的parse 方法得到parameterMappings 的具体实现中,我们会得到parameterMappings的typeHandlerTypeHandler typeHandler = parameterMapping.getTypeHandler();// 获取typeHandler 的jdbc typeJdbcType jdbcType = parameterMapping.getJdbcType();if (value == null && jdbcType == null) {jdbcType = configuration.getJdbcTypeForNull();}try {typeHandler.setParameter(ps, i + 1, 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);}}}}}
总结
总结一下ParameterHandler整体大致流程走向,以下面时序图为例