Mybatis源码动态代理调用

解析xml讲完之后,我们开始讲调用了。因为mybatis实际使用了动态代理(阉割版),不过这里的动态代理没有实现类。有关这块设计模式可以找一下看看。

public class Test {

    public static void main(String[] args) throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取代理
        PageArticlesMapper pageArticles = sqlSessionFactory.openSession().getMapper(PageArticlesMapper.class);
        //查询
        pageArticles.selectBlog(101);

    }
}

Mybatis源码动态代理调用_第1张图片

大家在这里注意到了proxy代理了吧,因为在之前解析xml的时候已经对每个xxMapper接口都包装了一个MapperProxyFactory,当从sqlSessionFactory.openSession().getMapper(PageArticlesMapper.class);获取对应的xxMapper时,会进行代理实例化。来看一下

DefaultSqlSession#getMapper

public <T> T getMapper(Class<T> type) {
  return configuration.<T>getMapper(type, this);
}

MapperRegistry#getMapper

//在这里获取对应xxxMapper的代理对象
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  //获取的类包装了一层代理工厂
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  if (mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  }
  try {
    //实例化
    return mapperProxyFactory.newInstance(sqlSession);
  } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  }
}

正好找到了之前对bean封装的MapperProxyFactory类

public <T> void addMapper(Class<T> type) {
  if (type.isInterface()) {
    //如果已经存在则报错  interface com.telecom.BlogMapper
    if (hasMapper(type)) {
      throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
    }
    boolean loadCompleted = false;
    try {
      //放入map中,并对类型包装一个代理工厂
      knownMappers.put(type, new MapperProxyFactory(type));
      // It's important that the type is added before the parser is run
      // otherwise the binding may automatically be attempted by the
      // mapper parser. If the type is already known, it won't try.
      MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
      parser.parse();
      loadCompleted = true;
    } finally {
      if (!loadCompleted) {
        knownMappers.remove(type);
      }
    }
  }
}

继续MapperProxyFactory#newInstance

protected T newInstance(MapperProxy<T> mapperProxy) {
  //通过代理进行实例化
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

public T newInstance(SqlSession sqlSession) {
  //包装代理
  final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}

然后进入 java.lang.reflect.Proxy#newProxyInstance,大家可以滤过下面这个代码

public static Object newProxyInstance(ClassLoader loader,
                                      Class[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    Objects.requireNonNull(h);

    final Class[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     * Look up or generate the designated proxy class.
     */
    Class cl = getProxyClass0(loader, intfs);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }

        final Constructor cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        return cons.newInstance(new Object[]{h});
    } catch (IllegalAccessException|InstantiationException e) {
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString(), t);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
}

继续到Test.java中

Mybatis源码动态代理调用_第2张图片

MapperProxy实现了InvocationHandler,那当调用这个接口的时候就会触发invoke方法。

MapperProxy#invoke

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  try {

    if (Object.class.equals(method.getDeclaringClass())) {
      //如果是从Object继承的方法,直接执行
      return method.invoke(this, args);
      //判断是否是默认方法,默认方法是Java8的新特性,判断逻辑与Java8 Method类的isDefault方法一样
    } else if (isDefaultMethod(method)) {
      //调用默认方法,这里面用到了Java7API,有兴趣的读者可以自行了解
      return invokeDefaultMethod(proxy, method, args);
    }
  } catch (Throwable t) {
    throw ExceptionUtil.unwrapThrowable(t);
  }
  /*构建并缓存MapperMethod*/
  final MapperMethod mapperMethod = cachedMapperMethod(method);
  /*执行*/
  return mapperMethod.execute(sqlSession, args);
}

private MapperMethod cachedMapperMethod(Method method) {
  //从缓存中获取信息 public abstract com.telecom.Blog com.telecom.BlogMapper.selectBlog(int)
  MapperMethod mapperMethod = methodCache.get(method);
  if (mapperMethod == null) {
    //加入缓存
    mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
    methodCache.put(method, mapperMethod);
  }
  return mapperMethod;
}

MapperMethod#execute

//根据type类型执行
public Object execute(SqlSession sqlSession, Object[] args) {
  Object result;
  switch (command.getType()) {
    case INSERT: {
      /*将参数转换为sql命令的参数*/
      Object param = method.convertArgsToSqlCommandParam(args);
      /*插入,返回影响行数的结果*/
      result = rowCountResult(sqlSession.insert(command.getName(), param));
      break;
    }
    case UPDATE: {
      /*将参数转换为sql命令的参数*/
      Object param = method.convertArgsToSqlCommandParam(args);
      /*更新,返回影响行数的结果*/
      result = rowCountResult(sqlSession.update(command.getName(), param));
      break;
    }
    case DELETE: {
      /*将参数转换为sql命令的参数*/
      Object param = method.convertArgsToSqlCommandParam(args);
      /*删除,返回影响行数的结果*/
      result = rowCountResult(sqlSession.delete(command.getName(), param));
      break;
    }
    case SELECT:
      //下面几个分支判断的条件,我们在分析构造MapperMethod的过程时看到了这些波尔条件的赋值过程
      if (method.returnsVoid() && method.hasResultHandler()) {
        /*返回void并且方法包含ResultHandler的查询的执行*/
        executeWithResultHandler(sqlSession, args);
        result = null;
      } else if (method.returnsMany()) {
        /*多个返回值的查询的执行*/
        result = executeForMany(sqlSession, args);
      } else if (method.returnsMap()) {
        /*@MapKey注解的Map类型的返回值的查询的执行*/
        result = executeForMap(sqlSession, args);
      } else if (method.returnsCursor()) {
        /*Cursor游标类型的返回值的查询的执行*/
        result = executeForCursor(sqlSession, args);
      } else {
        /*将参数转换为sql命令的参数*/
        Object param = method.convertArgsToSqlCommandParam(args);
        /*单个返回值的查询的执行*/
        result = sqlSession.selectOne(command.getName(), param);
      }
      break;
    case FLUSH:
      result = sqlSession.flushStatements();
      break;
    default:
      throw new BindingException("Unknown execution method for: " + command.getName());
  }
  //命令执行结果为null,并且方法返回值是基本类型抛出异常
  if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
    throw new BindingException("Mapper method '" + command.getName()
            + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
  }
  return result;
}

到这里,大家看到了增删改查的判断了吧。测试方法走select.

public Object getNamedParams(Object[] args) {
  final int paramCount = names.size();
  if (args == null || paramCount == 0) {
    return null; //解析的参数名称为空,返回null
  } else if (!hasParamAnnotation && paramCount == 1) {
    //没有注解@Param的参数并且解析的参数名称只有一个,根据下标返回参数
    return args[names.firstKey()];
  } else {
    final Map, Object> param = new ParamMap();
    int i = 0;
    for (Map.Entry, String> entry : names.entrySet()) {
      //添加参数命名和参数值的对应关系
      param.put(entry.getValue(), args[entry.getKey()]);
      //通用的参数名称,param1param2...
      final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
      if (!names.containsValue(genericParamName)) {
        //添加通用参数名称和参数值的对应关系
        param.put(genericParamName, args[entry.getKey()]);
      }
      i++;
    }
    return param;
  }
} 
  

通过selectOne一路追到DefaultSqlSession#selectList类中

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  try {
    //根据statementId获取MappedStatement
    MappedStatement ms = configuration.getMappedStatement(statement);
    return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}
//对集合类型参数的包装,就是如果参数是集合类型,会根据参数类型的不同为参数添加不同的key
private Object wrapCollection(final Object object) {
  if (object instanceof Collection) {
    StrictMap map = new StrictMap();
    map.put("collection", object);
    if (object instanceof List) {
      map.put("list", object);
    }
    return map;
  } else if (object != null && object.getClass().isArray()) {
    StrictMap map = new StrictMap();
    map.put("array", object);
    return map;
  }
  return object;
} 
  

这里的executor在默认配置的情况下的类型是CachingExecutor

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
  /*获取解析过动态标签的sql*/
  BoundSql boundSql = ms.getBoundSql(parameterObject);
  //创建缓存key
  CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
  /*调用另一个重载的查询方法进行查询*/
  return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
public BoundSql getBoundSql(Object parameterObject) {
  /*获取解析过动态标签的sql*/
  BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
  List parameterMappings = boundSql.getParameterMappings();
  if (parameterMappings == null || parameterMappings.isEmpty()) {
    boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
  }
  //检查参数映射中是否存在嵌套的resultMap并设置boolean标记
  for (ParameterMapping pm : boundSql.getParameterMappings()) {
    String rmId = pm.getResultMapId();
    if (rmId != null) {
      ResultMap rm = configuration.getResultMap(rmId);
      if (rm != null) {
        hasNestedResultMaps |= rm.hasNestedResultMaps();
      }
    }
  }
  return boundSql;
}

DynamicSqlSource#getBoundSql

public BoundSql getBoundSql(Object parameterObject) {
  DynamicContext context = new DynamicContext(configuration, parameterObject);
  //这里会根据动态标签的不同,如等,解析这些节点拼接到sql中,会涉及到OGNL表达式解析的内容,有兴趣的读者可以自行了解
  rootSqlNode.apply(context);
  SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
  Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
  //#{}替换成?号占位符,并构建每个占位符对应参数属性的映射
  SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
  //将解析内容封装到BoundSql对象中返回
  BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
  for (Map.Entry, Object> entry : context.getBindings().entrySet()) {
    boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
  }
  return boundSql;
}

BaseExecutor#createCacheKey

public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
  if (closed) {
    throw new ExecutorException("Executor was closed.");
  }
  //创建缓存
  //621272139:1884823062:com.telecom.BlogMapper.selectBlog:0:2147483647:select * from Blog where id = ?
  CacheKey cacheKey = new CacheKey();
  cacheKey.update(ms.getId());
  cacheKey.update(rowBounds.getOffset());
  cacheKey.update(rowBounds.getLimit());
  cacheKey.update(boundSql.getSql());
  List parameterMappings = boundSql.getParameterMappings();
  TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
  // mimic DefaultParameterHandler logic
  for (ParameterMapping parameterMapping : parameterMappings) {
    if (parameterMapping.getMode() != ParameterMode.OUT) {
      Object value;
      //获取属性名称
      String propertyName = parameterMapping.getProperty();
      if (boundSql.hasAdditionalParameter(propertyName)) {
        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);
      }
      //1512233168:1884823163:com.telecom.BlogMapper.selectBlog:0:2147483647:select * from Blog where id = ?:101
      cacheKey.update(value);
    }
  }
  if (configuration.getEnvironment() != null) {
    // 将环境的id更新进去
    cacheKey.update(configuration.getEnvironment().getId());
  }
  //-1230830222:1660009398:com.telecom.BlogMapper.selectBlog:0:2147483647:select * from Blog where id = ?:101:development
  return cacheKey;
}

这里的cacheKey会在一级缓存(Map)代码中作为key。查询结果为value。

CachingExecutor#query

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
    throws SQLException {
  //获取缓存信息,不过第一次调用没有
  Cache cache = ms.getCache();
  //不为空,判断从缓存获取
  if (cache != null) {
    flushCacheIfRequired(ms);
    if (ms.isUseCache() && resultHandler == null) {
      ensureNoOutParams(ms, boundSql);
      @SuppressWarnings("unchecked")
      List<E> list = (List<E>) tcm.getObject(cache, key);
      if (list == null) {
        list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        tcm.putObject(cache, key, list); // issue #578 and #116
      }
      return list;
    }
  }
  //缓存为空,则从数据库查询
  return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

BaseExecutor#query,这里的key是从cacheKey创建获得的

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
  if (closed) {
    throw new ExecutorException("Executor was closed.");
  }
  if (queryStack == 0 && ms.isFlushCacheRequired()) {
    clearLocalCache();
  }
  List<E> list;
  try {
    //计数器
    queryStack++;
    //从缓存拿去
    list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
    if (list != null) {
      handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
    } else {
      //从数据库读取
      list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
  } finally {
    queryStack--;
  }
  if (queryStack == 0) {
    for (DeferredLoad deferredLoad : deferredLoads) {
      deferredLoad.load();
    }
    // issue #601
    deferredLoads.clear();
    if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
      // issue #482
      clearLocalCache();
    }
  }
  return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  List<E> list;
  //设置缓存,占位符。防止其他连接调用击穿db
  localCache.putObject(key, EXECUTION_PLACEHOLDER);
  try {
    //执行  org.apache.ibatis.executor.SimpleExecutor.doQuery
    /*子类实现具体的查询逻辑*/
    list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
  } finally {
    localCache.removeObject(key);
  }
  localCache.putObject(key, list);
  if (ms.getStatementType() == StatementType.CALLABLE) {
    localOutputParameterCache.putObject(key, parameter);
  }
  return list;
}

SimpleExecutor#doQuery

/*子类实现具体的查询逻辑*/
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  Statement stmt = null;
  try {
    Configuration configuration = ms.getConfiguration();
    //包装StatementHandler
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
    /*准备Statement*/
    stmt = prepareStatement(handler, ms.getStatementLog());
    //查询
    return handler.<E>query(stmt, resultHandler);
  } finally {
    closeStatement(stmt);
  }
}
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  /*构造RoutingStatementHandler*/
  StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
  //拦截器执行
  statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
  return statementHandler;
}

RoutingStatementHandler

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  //根据statementType配置选择不同的处理器,在标签解析时我们看到默认为PREPARED
  switch (ms.getStatementType()) {
    case STATEMENT:
      delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
      break;
    case PREPARED:
      delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
      break;
    case CALLABLE:
      delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
      break;
    default:
      throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
  }

}
SimpleExecutor

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
  Statement stmt;
  //获取数据库连接
  Connection connection = getConnection(statementLog);
  /*准备Statement*/
  stmt = handler.prepare(connection, transaction.getTimeout());
  /*Statement设置参数*/
  handler.parameterize(stmt);
  return stmt;
}

BaseStatementHandler

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
  /*实例化Statement*/
        statement = instantiateStatement(connection);
    /*设置超时时间*/
        setStatementTimeout(statement, transactionTimeout);
    /*设置FetchSize*/
        setFetchSize(statement);
        return statement;
    } catch (SQLException e) {
        closeStatement(statement);//异常关闭Statement
        throw e;
    } catch (Exception e) {
        closeStatement(statement);//异常关闭Statement
        throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
}

instantiateStatement实例化Statement就是根据配置不同调用Connection的不同重载方法来创建PreparedStatement,具体每个重载的方法的作用,请参考Java API。

protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {
    Integer queryTimeout = null;
    //标签上配置的timeout优先级最高
    if (mappedStatement.getTimeout() != null) {
        queryTimeout = mappedStatement.getTimeout();
    } else if (configuration.getDefaultStatementTimeout() != null) {
        //标签没有配置则应用全局配置的timeout
        queryTimeout = configuration.getDefaultStatementTimeout();
    }
    if (queryTimeout != null) {
        stmt.setQueryTimeout(queryTimeout);
    }
      /*应用事务超时时间*/
    StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout);
}
public static void applyTransactionTimeout(Statement statement, Integer queryTimeout, Integer transactionTimeout) throws SQLException {
  if (transactionTimeout == null){
    return;
  }
  Integer timeToLiveOfQuery = null;
  //没有配置查询超时时间则应用事务配置的超时时间
  if (queryTimeout == null || queryTimeout == 0) {
    timeToLiveOfQuery = transactionTimeout;
  } else if (transactionTimeout < queryTimeout) {
    //如果事务配置的超时时间小于配置的查询超时时间,则应用事务配置的超时时间
    timeToLiveOfQuery = transactionTimeout;
  }
  if (timeToLiveOfQuery != null) {
    statement.setQueryTimeout(timeToLiveOfQuery);
  }
}

BaseStatementHandler#setFetchSize

protected void setFetchSize(Statement stmt) throws SQLException {
    //标签上配置的优先
    Integer fetchSize = mappedStatement.getFetchSize();
    if (fetchSize != null) {
        stmt.setFetchSize(fetchSize);
        return;
    }
    Integer defaultFetchSize = configuration.getDefaultFetchSize();
    if (defaultFetchSize != null) {
        //标签上没有配置则使用全局配置
        stmt.setFetchSize(defaultFetchSize);
    }
}

回到SimpleExecutor#prepareStatement并继续跟踪到PreparedStatementHandler#parameterize,直到DefaultParameterHandler#setParameters

public void setParameters(PreparedStatement ps) {
  ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
  List parameterMappings = boundSql.getParameterMappings();
  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 jdbcType = parameterMapping.getJdbcType();
        if (value == null && jdbcType == null) {
          jdbcType = configuration.getJdbcTypeForNull();
        }
        try {
           /*PreparedStatement设置值*/
          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);
        }
      }
    }
  }
}
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
  if (parameter == null) {
    if (jdbcType == null) {
      throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
    }
    try {
      //设置空值
      ps.setNull(i, jdbcType.TYPE_CODE);
    } catch (SQLException e) {
      throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
              "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
              "Cause: " + e, e);
    }
  } else {
    try {
      //子类实现具体的非空值设置
      setNonNullParameter(ps, i, parameter, jdbcType);
    } catch (Exception e) {
      throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
              "Try setting a different JdbcType for this parameter or a different configuration property. " +
              "Cause: " + e, e);
    }
  }
}
根据构建ParameterMapping时设置的TypeHandler来为PreparedStatement设置对应类型的值。 

RoutingStatementHandler:

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  //org.apache.ibatis.executor.statement.PreparedStatementHandler.query
  return delegate.<E>query(statement, resultHandler);
}
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  PreparedStatement ps = (PreparedStatement) statement;
  ps.execute(); //执行sql命令 返回com.mysql.jdbc.JDBC42PreparedStatement@1a677343: select * from Blog where id = 101
  /*处理结果集*/
  return resultSetHandler.<E> handleResultSets(ps);
}

到这里就要进入mysql驱动程序对接数据库了。然后查询结果handleResultSets在这里不讲,有兴趣的可以查看阅读以下,否则整个章节太长,难以消化。


上一篇: Mybatis之Xml解析说明

 下一篇: Spring-Mybatis 注解连接器 MapperScannerRegistrar

你可能感兴趣的:(Mybatis,源码分析)