`
shuidexiongdi
  • 浏览: 73400 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Ibatis源码学习(二):延迟加载的实现

 
阅读更多

Ibatis获取查询的结果是从ResultMap.java类里面的getResults获取

 

/**
   * Read a row from a resultset and map results to an array.
   *
   * @param statementScope scope of the request
   * @param rs ResultSet to read from
   *
   * @return row read as an array of column values.
   *
   * @throws java.sql.SQLException
   */
  public Object[] getResults(StatementScope statementScope, ResultSet rs)
      throws SQLException {
      ...
      for (int i = 0; i < getResultMappings().length; i++) {
      ...
         columnValues[i] = getNestedSelectMappingValue(statementScope, rs, mapping, javaType);
     ...
     }
}

 getNestedSelectMappingValue方法的调用如下:

 

protected Object getNestedSelectMappingValue(StatementScope statementScope, ResultSet rs, ResultMapping mapping, Class targetType)
      throws SQLException {
    try {
      ...
        result = ResultLoader.loadResult(client, statementName, parameterObject, targetType);

       ...
      return result;
    } catch (InstantiationException e) {
      throw new NestedSQLException("Error setting nested bean property.  Cause: " + e, e);
    } catch (IllegalAccessException e) {
      throw new NestedSQLException("Error setting nested bean property.  Cause: " + e, e);
    }

  }

 

 这时调用的是ResultLoader.loadResult方法:

 

/**
   * Loads a result lazily
   *
   * @param client          - the client creating the object
   * @param statementName   - the name of the statement to be used
   * @param parameterObject - the parameters for the statement
   * @param targetType      - the target type of the result
   * @return the loaded result
   * @throws SQLException
   */
  public static Object loadResult(SqlMapClientImpl client, String statementName, Object parameterObject, Class targetType)
      throws SQLException {
    Object value = null;


    if (client.isLazyLoadingEnabled()) {
      if (client.isEnhancementEnabled()) {
        EnhancedLazyResultLoader lazy = new EnhancedLazyResultLoader(client, statementName, parameterObject, targetType);
        value = lazy.loadResult();
      } else {
        LazyResultLoader lazy = new LazyResultLoader(client, statementName, parameterObject, targetType);
        value = lazy.loadResult();
      }
    } else {
      value = getResult(client, statementName, parameterObject, targetType);
    }

    return value;
  }

 

 注意下面的调用:

(调用CGLIB的方式代理这里暂不分析,先分析利用java反射API进行的动态代理方式)

 

LazyResultLoader lazy = new LazyResultLoader(client, statementName, parameterObject, targetType);

        value = lazy.loadResult();

LazyResultLoader 是实现InvocationHandler的代理动态类,里面的方法如下:

 

/**
   * Loads the result
   *
   * @return the results - a list or object
   * 
   * @throws SQLException if there is a problem
   */
  public Object loadResult() throws SQLException {
    if (Collection.class.isAssignableFrom(targetType)) {
      InvocationHandler handler = new LazyResultLoader(client, statementName, parameterObject, targetType);
      ClassLoader cl = targetType.getClassLoader();
      if (Set.class.isAssignableFrom(targetType)) {
        return Proxy.newProxyInstance(cl, SET_INTERFACES, handler);
      } else {
        return Proxy.newProxyInstance(cl, LIST_INTERFACES, handler);
      }
    } else {
      return ResultLoader.getResult(client, statementName, parameterObject, targetType);
    }
  }
 

方法里面对所有的collection作为父接口的类都采用了创建代理对象的方式进行了延迟加载,对所有set的采用的set的方式,所有非set的采用list的方式(也即是对所有的子查询进行了延迟加载)。所有的非collectin子类都采用非延迟加载的方式加载。

 

 

这里先创建一个代理对象,待真正用到对象的数据时,将执行动态代理的invoke方法,然后在invoke方法里面才真正的加载数据。

public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
    if ("finalize".hashCode() == method.getName().hashCode()
        && "finalize".equals(method.getName())) {
      return null;
    } else {
      loadObject();
      if (resultObject != null) {
        try {
          return method.invoke(resultObject, objects);
        } catch (Throwable t) {
          throw ClassInfo.unwrapThrowable(t);
        }
      } else {
        return null;
      }
    }
  }
 
 private synchronized void loadObject() {
    if (!loaded) {
      try {
        loaded = true;
        resultObject = ResultLoader.getResult(client, statementName, parameterObject, targetType);
      } catch (SQLException e) {
        throw new RuntimeException("Error lazy loading result. Cause: " + e, e);
      }
    }
  }
 
实际的加载数据是通过ResultLoader.getResult(client, statementName, parameterObject, targetType);里面的实际加载委托为SqlMapClientImpl的数据加载:
 protected static Object getResult(SqlMapClientImpl client, String statementName, Object parameterObject, Class targetType) throws SQLException {
    Object value = null;
    if (DomCollectionTypeMarker.class.isAssignableFrom(targetType)) {
      value = client.queryForList(statementName, parameterObject);
    } else if (Set.class.isAssignableFrom(targetType)) {
      value = new HashSet(client.queryForList(statementName, parameterObject));
    } else if (Collection.class.isAssignableFrom(targetType)) {
      value = client.queryForList(statementName, parameterObject);
    } else if (targetType.isArray()) {
      List list = client.queryForList(statementName, parameterObject);
      value = listToArray(list, targetType.getComponentType());
    } else {
      value = client.queryForObject(statementName, parameterObject);
    }
    return value;
  }
 

 

 

备注:初稿,为写完,后续继续。

分享到:
评论

相关推荐

    iBatis2学习笔记

    1.iBatis2学习笔记:基本原理和配置.doc 2.iBatis2学习笔记:与Spring2的整合.doc 3.iBatis2学习笔记:单表映射 .doc 4.iBatis2学习笔记:SqlMap的配置总结(18条).doc 5.iBatis2学习笔记:入参和返回值的问题.doc ...

    ibatis源码

    描述中的"ibatis框架源码剖析书中附带的光盘,ibatis源码分析"暗示这可能是一个学习资源,用于深入理解iBATIS的工作原理,可能包括了对源码的详细解读和分析。 **iBATIS核心知识点** 1. **SQL映射**:iBATIS的核心...

    ibatis源码,ibatis源码 ibatis源码 ibatis源码

    源码中`org.apache.ibatis.cache.Cache`接口定义了缓存的基本操作,而具体的缓存实现如`org.apache.ibatis.cache.impl.PerpetualCache`则实现了缓存的存储和读取。 通过阅读和理解iBatis的源码,我们可以更深入地...

    最新ibatis 源码

    ibatis源码 学习参考 对于学习ibatis很有帮助

    iBATIS 三个版对比

    ### iBATIS 三个版本对比分析 iBATIS是一款优秀的持久层框架,它极大地简化了SQL映射编程的复杂度。随着技术的发展,iBATIS经历了多个版本的迭代,包括iBATIS v1、v2以及最新的iBATIS v3。本文将详细对比这三个版本...

    ibatis源码+api文档+jar包

    3. 学习设计模式:Ibatis的源码中应用了许多经典的设计模式,如工厂模式、单例模式、代理模式等,这对于提升编程技能非常有帮助。 最后,API文档是开发者的重要参考材料,它详细解释了每个类、接口和方法的功能、...

    iBATIS框架源码剖析源码

    通过深入分析iBATIS的源码,开发者不仅可以了解其工作原理,还能学习到设计模式、数据库访问的最佳实践以及如何优雅地处理数据库操作。对于提升Java开发者的技能和理解数据库访问层的实现有极大的帮助。在实际开发中...

    iBATIS框架源码剖析

    iBATIS框架源码剖析

    实现ibatis手动控制加载sqlmap文件,终于不用重启应用了

    综上所述,通过监听文件系统变化并自定义SqlSessionFactory,我们可以实现在不重启应用的情况下手动控制加载iBatis的SQL映射文件。这极大地提高了开发效率,同时也对开发流程提出了更高的要求,比如需要更严格的文件...

    iBATIS框架源码剖析pdf第二部分

    iBATIS是一个开源的...总之,"iBATIS框架源码剖析pdf第二部分"将带你深入iBATIS的内部,揭示其设计思想和实现细节。通过学习,你不仅可以提升对iBATIS的理解,还能为使用或开发类似的数据库访问框架打下坚实的基础。

    ibatis2.3源码

    通过深入研究iBATIS 2.3的源码,开发者不仅可以了解其实现细节,还可以学习到如何设计一个高效的持久层框架,提升自己的编程技巧和设计能力。同时,这也为那些希望在现有基础上定制或优化iBATIS功能的开发者提供了...

    iBatis框架源码剖析

    iBATIS一词来源于“internet”和“abatis”的组合,是一个由Clinton Begin在2001年发起的开放源代码项目。于2010年6月16号被谷歌托管,改名为MyBatis。是一个基于SQL映射支持Java和·NET的持久层框架。

    ibatisDemo 入门源码

    《IbatisDemo入门源码详解》 IbatisDemo是一个典型的基于Ibatis框架的入门示例,它为我们展示了如何在Java项目中使用Ibatis进行数据库操作。Ibatis,一个优秀的持久层框架,它允许开发者将SQL语句直接写在配置文件...

    ibatis框架源码剖析光盘资料

    总的来说,ibatis框架源码的学习不仅可以帮助我们理解其工作原理,提升开发效率,还能为我们提供一种思考问题的角度,理解数据访问层的设计模式。通过对源码的深入剖析,我们可以更好地解决实际项目中的问题,进行...

    iBATIS2.3.4 jar包及源码

    对于开发者来说,源码能够帮助他们深入了解iBATIS的工作原理,便于学习、调试和扩展。如果在使用过程中遇到问题,查看源码可以快速定位并解决问题。通常,将源码放在`lib`目录下并不常见,因为源码主要用于开发和...

    ibatis 学习源码

    PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd"&gt; cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="true" ...

    ibatis学习资料汇总

    《iBatis学习资料汇总》 iBatis,作为一个轻量级的持久层框架,它在Java开发领域中扮演着重要的角色。这个框架允许开发者将SQL语句与Java代码分离,提高了开发效率并降低了维护成本。本文将深入探讨iBatis的核心...

Global site tag (gtag.js) - Google Analytics