【问题标题】:Postgresql, JDBC, and streaming BLOBsPostgresql、JDBC 和流式处理 BLOB
【发布时间】:2011-01-05 09:17:47
【问题描述】:

我正在尝试使用 jdbc 驱动程序从 postgres 数据库中检索 blob。它太大而无法存储在内存中,所以我想将其作为下载流式传输。我尝试在 ResultSet 上使用 getBinaryStream 方法,但事实证明该方法实际上将其全部读入内存,因此不适用于大文件。

显然,可以在结果集上使用 getBlob 方法,并且大概从 blob 获取输入流并从那里开始,但这就是我遇到问题的地方。

PreparedStatement ps = con.prepareStatement("select data from file_data WHERE ID = ?");
ps.setLong(1,file.fileData.id)
ResultSet rs = ps.executeQuery()
if(rs.next()){
        rs.getBlob("data")

这就是我正在运行的代码。当它到达最后一行时,它会抛出一个我无法理解的错误......

org.postgresql.util.PSQLException:long 类型的值错误:xxxxxx

"xxxxxx" 然后是文件的内容。你可以想象这会变得很长,但不是重点。

我被困在这里了。有人对发生的事情有任何想法吗?哎呀,我什至会采用其他方法来流式传输大型 blob 作为下载。

【问题讨论】:

  • 在我的例子中是rs.getBlob(...)而不是rs.getBinaryStream(...)。学习 JDBC 永远不要迟到。

标签: java postgresql jdbc blob


【解决方案1】:

我的猜测是,您混淆了 OID 和 BYTEA 样式的 blob。大型二进制对象在 Postgres 中使用 OID 列间接存储。实际的文件数据由 Postgres 存储在数据库表之外的某个地方。该列仅包含与 Blob 内部关联的对象标识符。例如:

janko=# CREATE TABLE blobtest1 (name CHAR(30), image OID);
CREATE TABLE                                              
janko=# INSERT INTO blobtest1 VALUES ('stackoverflow', lo_import('/tmp/stackoverflow-logo.png'));
INSERT 0 1
janko=# SELECT * FROM blobtest1;
              name              | image
--------------------------------+-------
 stackoverflow                  | 16389
(1 row)

如果您使用ResultSet#getBlob(String) 方法,则需要使用 OID 样式列。 getBlob 从列中读取数据并将其转换为Long。然后它会尝试从其内部存储中读取相关的二进制数据。

另一方面,使用 BYTEA,您可以将小块二进制数据直接放入数据库中。例如:

janko=# CREATE TABLE blobtest2 (name CHAR(30), image BYTEA);
CREATE TABLE
janko=# INSERT INTO blobtest2 VALUES ('somebinary', E'\\336\\255\\276\\357\\336\\255\\276\\357');
INSERT 0 1
janko=# SELECT * FROM blobtest2;
              name              |              image
--------------------------------+----------------------------------
 somebinary                     | \336\255\276\357\336\255\276\357
(1 row)

这里,数据列直接包含二进制数据。如果您尝试在此类列上使用getBlob,数据仍将被解释为 OID,但显然它不适合Long。让我们在刚刚创建的数据库上试试这个:

groovy:000> import java.sql.*
===> [import java.sql.*]
groovy:000> Class.forName("org.postgresql.Driver");
===> class org.postgresql.Driver
groovy:000> db = DriverManager.getConnection("jdbc:postgresql:janko", "janko", "qwertz");
===> org.postgresql.jdbc4.Jdbc4Connection@3a0b2c64
groovy:000> ps = db.prepareStatement("SELECT image FROM blobtest2 WHERE name = ?");
===> SELECT image FROM blobtest2 WHERE name = ?
groovy:000> ps.setString(1, "somebinary")
===> null
groovy:000> rs = ps.executeQuery()
===> org.postgresql.jdbc4.Jdbc4ResultSet@66f9104a
groovy:000> rs.next()
===> true
groovy:000> rs.getBlob("image")
ERROR org.postgresql.util.PSQLException: Bad value for type long : \336\255\276\357\336\255\276\357
        at org.postgresql.jdbc2.AbstractJdbc2ResultSet.toLong (AbstractJdbc2ResultSet.java:2796)
        at org.postgresql.jdbc2.AbstractJdbc2ResultSet.getLong (AbstractJdbc2ResultSet.java:2019)
        at org.postgresql.jdbc4.Jdbc4ResultSet.getBlob (Jdbc4ResultSet.java:52)
        at org.postgresql.jdbc2.AbstractJdbc2ResultSet.getBlob (AbstractJdbc2ResultSet.java:335)
        at groovysh_evaluate.run (groovysh_evaluate:3)
        ...

【讨论】:

  • 谢谢!所以 rs.getBytes("image") 为我工作以获取 byteArray :-)
【解决方案2】:

“存储二进制数据”的 PostgreSQL 文档有帮助吗?

http://jdbc.postgresql.org/documentation/head/binary-data.html

页面底部标题为“从大对象中检索图像”的部分可能会有所帮助。

【讨论】:

    【解决方案3】:
    byte [] b = null;
    while (m_ResultSet.next()) {
        for (int i = 1; i <= m_ResultSet.getMetaData().getColumnCount(); i++) {
            b =  m_ResultSet.getBytes(i);
        }
    }
    String str = "";
    for (byte i : b){
        str+=(char)i;
    }
    

    【讨论】:

    • 请考虑为代码的作用或不同之处添加解释。
    猜你喜欢
    • 2018-04-25
    • 1970-01-01
    • 2010-10-26
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-07
    • 2015-02-18
    相关资源
    最近更新 更多