美文网首页程序员
Mybatis|SqlSession四大对象(二)

Mybatis|SqlSession四大对象(二)

作者: GGarrett | 来源:发表于2018-11-29 00:05 被阅读0次

1. SqlSession中四大神器之ParameterHandler

1.1 ParameterHandler介绍

参数处理器负责为ParameterHandler的sql语句参数动态赋值。

/**
 * A parameter handler sets the parameters of the {@code PreparedStatement}
 *
 * @author Clinton Begin
 */
public interface ParameterHandler {

  Object getParameterObject();

  void setParameters(PreparedStatement ps)
      throws SQLException;

}

这个接口中只有两个方法:
getParameterObject 方法用于读取参数。
setParameters用于对ParameterHandler的参数赋值。

1.2 ParameterHandler对象创建

参数处理器对象时在创建StatementHandler对象时同时被创建的,由configuration对象负责创建。

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 statement
      generateKeys(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);
  }

创建时传入三个对象:mappedStatement(执行SQL对应的配置信息)、parameterObject、boundSql。

注意:一个BoundSql对象,代表了SQL语句的一次执行,而SqlSource对象的责任就是根据传入的参数对象动态计算出这个BoundSql,也就是说Mapper文件中的节点的计算是由SqlSource对象完成的。SqlSource最常用是实现类是DynamicSqlSource。

1.3 ParameterHandler中的参数从何而来?
 @Test
     public void Test01(){
            DeptDao dao =  session.getMapper(DeptDao.class);
            Dept dept = dao.findByDeptNo(10);
            System.out.println(dept.getDname());
     }

看看上述的实参10是如何添加到对应的SQL语句中的

 <select id="findByDeptNo" resultType="dept">
        <include refid="DeptFindSql"></include>
        where deptno = #{deptNo}
   </select>

在MyBatis中,使用动态代理模式,当dao.findByDeptNo(10)将要执行的时候,会被JVM进行拦截交给MyBatis中的代理实现类MapperProxy中的invoke方法。

@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

最后交给ParameterHandler中setParameter方法,将参数交给对应占位符。

 @Override
  public Object getParameterObject() {
    return parameterObject;
  }

@Override
  public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    //parameterMappings  是对#{}里面的参数的封装,
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    //如果是参数化sql(sql语句中带占位符?)便要设置参数   
    if (parameterMappings != null) {
      for (int i = 0; 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);
          }
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          JdbcType 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);
          }
        }
      }
    }
  }

读取ParameterObject参数对象,然后用typeHandler对参数进行设置,而typeHandler里面需要对jdbcType和javaType进行处理,设置参数。所以使用TypeHandler的时候完全可以控制如何设置SQL参数。

2. Sqlsession四大神器之ResultSetHandler

2.1 ResultSetHandler介绍

ResultSetHandler接口主要负责两件事:

  • 处理Statement执行后产生的结果集,生成结果列表。
  • 处理存储过程执行后的输出参数 。
/**
 * @author Clinton Begin
 */
public interface ResultSetHandler {

  <E> List<E> handleResultSets(Statement stmt) throws SQLException;

  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;

  void handleOutputParameters(CallableStatement cs) throws SQLException;

}

相关文章

网友评论

    本文标题:Mybatis|SqlSession四大对象(二)

    本文链接:https://www.haomeiwen.com/subject/hzctcqtx.html