Postgresql,JDBC和流式BLOB [英] Postgresql, JDBC, and streaming BLOBs

查看:810
本文介绍了Postgresql,JDBC和流式BLOB的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

  PreparedStatement ps = con.prepareStatement(从file_data中选择数据WHERE ID =?); 
ps.setLong(1,file.fileData.id)
ResultSet rs = ps.executeQuery()
if(rs.next()){
rs.getBlob(数据)

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


org.postgresql.util.PSQLException :long类型的值不正确:xxxxxx


xxxxxx然后是文件的内容。你可以想象这会很长,但不是真的。



我被困在这里。有没有人对正在发生的事情有任何想法?哎呀我甚至会采取其他方法来流式传输大blob作为下载。

解决方案

我的猜测是,你已经混淆了OID和BYTEA风格的blob。大型二进制对象与Postgres中的OID列间接存储。 Postgres将实际文件数据存储在数据库表之外的某个地方。该列只包含一个与blob内部关联的对象标识符。例如:

  janko = #CREATE TABLE blobtest1(名称CHAR(30),图像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行)

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



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

  janko = #CREATE TABLE blobtest2(名称CHAR(30),图像BYTEA); 
CREATE TABLE
扬科=#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 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

这里,数据列直接包含二进制数据。如果您尝试在此类列上使用 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( 图像)
错误org.postgresql.util.PSQLException:long类型错误值:\336\255\276\357\336\255\276\ 357
处org.postgresql.jdbc2.AbstractJdbc2ResultSet.getLong(AbstractJdbc2ResultSet.java:2019)
org.postgresql.jdbc2.AbstractJdbc2ResultSet.toLong(AbstractJdbc2ResultSet.java:2796)
。在组织。在groovysh_evaluate.run postgresql.jdbc4.Jdbc4ResultSet.getBlob(Jdbc4ResultSet.java:52)
。在org.postgresql.jdbc2.AbstractJdbc2ResultSet.getBlob(AbstractJdbc2ResultSet.java:335)
(groovysh_evaluate:3)
...


I am trying to retrieve a blob from a postgres database using the jdbc drivers. It is too big to have in memory so I want to stream it as a download. I tried using the getBinaryStream method on ResultSet, but it turns out that this method actually reads it all into memory, so doesn't work for large file.

Apparently, one can use the getBlob method on the resultset and the presumeably get the inputstream from the blob and go from there, but that is where I run into my problem.

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")

That is the code I'm running. When it gets to that last line it throw out an error that I cannot make sense of...

org.postgresql.util.PSQLException: Bad value for type long : xxxxxx

"xxxxxx" then is the contents of the file. You can imagine that gets quite long, but not really the point.

I'm stuck here. Does anyone have any ideas on what is going on? Heck I'll even take alternative methods for streaming large blobs as a download.

解决方案

My guess is, that you have mixed up OID and BYTEA style blobs. Large binary objects are stored indirecty with OID columns in Postgres. The actual file data is stored somewhere outside the database table by Postgres. The column just contains an object identifier that is associated internally with the blob. For instance:

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)

If you use the ResultSet#getBlob(String) method, than an OID style column is expected. getBlob reads the data from the column and converts it to a Long. Then it tries to read the associated binary data from its internal storage.

On the other hand, with BYTEA you can place small pieces of binary data directly in your DB. For instance:

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)

Here, the data column directly contains the binary data. If you try to use getBlob on such a column, the data will still be interpreted as an OID but obviously it will not fit into a Long. Let's try this on the database, we just created:

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)
        ...

这篇关于Postgresql,JDBC和流式BLOB的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆