【问题标题】:Spring JDBC support and large datasetSpring JDBC 支持和大型数据集
【发布时间】:2010-11-23 09:33:23
【问题描述】:

当使用各种 JDBC 模板方法之一时,我对如何迭代/滚动大型结果集(不适合内存)感到困惑。即使没有直接暴露 Iterable 接口,我至少希望 RowCallbackHandler 的实例被调用查询正在执行而不是在它完成之后(或堆溢出)。

我确实看过this(尽管在精神上与堆栈溢出时的this post 相似,但对我没有任何改变)和春季论坛中的this 帖子。后者似乎表明回调处理程序确实应该在游标获取数据时被调用。然而,我的测试没有显示出这样的行为。

数据库是Oracle10g。我正在使用 11.1.0.7.0-Production 驱动程序和 Spring 2.5.6.SEC01。任何人都知道如何迭代结果集,最好同时保留 RowMapper 等的映射逻辑?

【问题讨论】:

    标签: java oracle spring jdbc


    【解决方案1】:
    1. 创建扩展StoredProcedure 的自定义存储过程
    2. 创建一个RowCallBackHandler,它可以一次处理每一行。
    3. 声明您的参数。如果您有结果集,请先声明该结果集。使用 SqlReturnResultSet 类并使用您的 RowCallBackHandler 创建它
    4. 声明任何其他参数
    5. 编译
    6. 我在客户存储过程的构造函数中执行了步骤 2 到 5
    7. 创建包含输入参数的地图
    8. 使用输入参数执行存储过程

    我会提供代码,但以下文章包含所有这些信息。

    Calling Stored Procedures with Spring JDBC Templates

    【讨论】:

      【解决方案2】:

      您可以使用springjdbc-iterable 库:

      CloseableIterator<MyObj> iter = jt.queryForIter("select ...", params, mapper);
      

      迭代器将在耗尽时自动关闭,也可以手动关闭。它只在事务范围内起作用。

      免责声明:我编写了这个库

      【讨论】:

        【解决方案3】:

        这是一个很好的库,用于将 java sql 结果集全部拉入内存。

        http://casperdatasets.googlecode.com

        您可以滚动/迭代数据集,可以针对它发出查询,并构建索引以进行优化。它还实现了 java.sql.resultset 接口,因此您可以继续对来自该数据集的结果进行操作,只需对您的 jdbc 代码进行最少的更改。

        【讨论】:

        • 它还有一个适配器,可以将 jdbc 结果集转换为内存结果集 - 我假设您可以在 spring jdbc 结果回调方法中调用此适配器。
        • 抱歉,但是“如何迭代/滚动大型结果集(不适合内存)”。
        【解决方案4】:

        Oracle JDBC 驱动程序对java.sql.Statement 上的setFetchSize() 方法具有适当的支持,这使您可以控制驱动程序一次获取多少行。

        然而,Spring 使用的RowMapper 的工作原理是将每一行读入内存,让RowMapper 将其转换为一个对象,并将每一行的对象存储在一个大列表中。如果您的结果集很大,那么无论 JDBC 如何获取行数据,此列表都会变大。

        如果您需要处理大型结果集,则 RowMapper 不可扩展。您可以考虑使用 RowCallbackHandler 以及 JdbcTemplate 上的相应方法。 RowCallbackHandler 没有规定结果的存储方式,由您自己决定。

        【讨论】:

        • setFetchSize 并没有为我改变任何事情,我之前尝试过使用它。您是否针对 Oracle 实例进行开发?对我来说,RowCallBackHandler 只是挂起,等待查询完成,正如我在 OP 中所写的那样。
        • 显然我在测试中忘记了对 JDBC 模板的 afterPropertiesSet() 调用。尴尬,但现在可以了:*)
        【解决方案5】:

        是否将数据流式传输回您或是否将其以一个块的形式发送回是驱动程序/连接的属性。例如,在 SQL Server 中,您在连接 URL 上使用 SelectMethod 属性:

        jdbc:microsoft:sqlserver://gsasql03:1433;DatabaseName=my_db;SelectMethod=direct

        direct 的值表示结果应该是一次性的。另一个选择是 cursor,它允许您指定您希望连接将结果流回给您。我不确定 Oracle 数据源的类比是什么,恐怕

        RowCallbackHandler 当然对我有用。

        【讨论】:

        • 是的,理想情况下您不放入数据集,您会在保持连接打开的同时获取记录,询问是否有更多记录。我在 .NET 中完成了这项工作,并在性能上获得了相当不错的提升。我想java会有类似的东西存在,尤其是在春天。
        • @*Zoidberg* - OP 似乎在做正确的事情,使用行回调处理程序
        • 这听起来很有希望。不幸的是,我在 Oracle JDBC 文档中找不到类似于此 SQL Server URL 设置的任何内容。
        猜你喜欢
        • 2019-01-26
        • 2013-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-06
        • 2016-07-28
        相关资源
        最近更新 更多