java – Postgresql,JDBC和流BLOB

我试图使用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: Bad value for type long : xxxxxx

“xxxxxx”就是文件的内容。你可以想象得到相当长的时间,但不是真的。

我被困在这里有人对发生了什么有任何想法吗?我甚至会采用替代方法来流式传输大型Blob作为下载。

最佳答案
我的猜测是,你混合了OID和BYTEA风格的斑点。大型二进制对象与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)
        ...

转载注明原文:java – Postgresql,JDBC和流BLOB - 代码日志