【问题标题】:Streaming big files from postgres database into file system using JDBC使用 JDBC 将大文件从 postgres 数据库流式传输到文件系统
【发布时间】:2019-11-27 06:12:54
【问题描述】:

我在我的 postgres 数据库中将文件存储在 bytea 类型的列中,其大小可能会超过分配的 Java 堆空间,因此在尝试将这些文件写入文件系统时,我很快就会遇到内存不足的问题。

我正在使用 JDBC 执行查询,然后将内容提取为二进制流。

这是我的代码的简化版本:

    public File readContent(String contentId) {
        PreparedStatement statement = jdbcTemplate.getDataSource().getConnection().prepareStatement("SELECT content from table.entry WHERE id=?");
        statement.setString(1, contentId);
        ResultSet resultSet = statement.executeQuery();
        resultSet.next();
        File file = writeToFileSystem(resultSet.getBinaryStream(1));
        resultSet.close();
        return file;
    }


    private File writeToFileSystem(InputStream inputStream) {
        File dir = createDirectories(Paths.get(properties.getTempFolder(), UUID.randomUUID().toString())).toFile();
        File file = new File(dir, "content.zip");
        FileUtils.copyInputStreamToFile(inputStream, file);
        return file;
    }

我的期望是,这可以让我将数据库中的数据流式传输到文件中,而无需将其完全加载到内存中。但是,这种方法不起作用,因为一旦执行查询,我仍然会收到 OutOfMemoryErrors

Caused by: java.lang.OutOfMemoryError: Java heap space
    at org.postgresql.core.PGStream.receiveTupleV3(PGStream.java:395)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2118)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:288)
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:430)
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:356)
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:168)
    at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:116)
    at sun.reflect.GeneratedMethodAccessor201.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114)
    at com.sun.proxy.$Proxy149.executeQuery(Unknown Source)
    at [...].ContentRepository.readContent(ContentRepository.java:111)  

有什么方法可以将数据库中的数据流式传输到文件中,而无需增加 Java VM 的可用内存?

【问题讨论】:

    标签: java postgresql jdbc blob


    【解决方案1】:

    根据this mail group discussion,您不应在此用例中使用bytea

    在pg中存储二进制数据有两种方法,它们有不同的 访问方法和性能特征。字节茶数据有望 更短,并由服务器与 ResultSet 一起返回。为了 您想使用返回指针(oid)的大型对象的较大数据 然后您可以随意从服务器流式传输的实际数据。

    此页面描述了两者之间的一些差异,并且 演示了使用 pg 特定的 api 来访问大对象,但是 getBlob/setBlob 可以正常工作。

    请参阅Chapter 7. Storing Binary Data 显示示例代码和Chapter 35. Large Objects 详细介绍:

    PostgreSQL 有一个大对象工具,它提供对存储在特殊大对象结构中的用户数据的流式访问。当处理太大而无法方便地作为一个整体进行操作的数据值时,流式访问非常有用。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-26
    • 1970-01-01
    • 2014-05-04
    • 2018-07-15
    相关资源
    最近更新 更多