2010-01-15 18 views
19

Estoy tratando de recuperar un blob de una base de datos de postgres usando los controladores jdbc. Es demasiado grande para tener en la memoria así que quiero transmitirlo como una descarga. Intenté usar el método getBinaryStream en ResultSet, pero resulta que este método realmente lo lee todo en la memoria, por lo que no funciona para archivos grandes.Postgresql, JDBC y BLOB de transmisión

Aparentemente, uno puede usar el método getBlob en el conjunto de resultados y obtener presumiblemente la corriente de entrada del blob e ir desde allí, pero ahí es donde me encuentro con mi problema.

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

Ese es el código que estoy ejecutando. Cuando se llega a la última línea se lanza hacia fuera un error que no puedo darle sentido ...

org.postgresql.util.PSQLException: Mala relación tipo long: xxxxxx

"xxxxxx "entonces es el contenido del archivo. Puedes imaginar que eso es bastante largo, pero realmente no es el punto.

Estoy atrapado aquí. ¿Alguien tiene alguna idea sobre lo que está pasando? Diablos, incluso tomaré métodos alternativos para transmitir grandes blobs como descarga.

+0

En mi caso fue 'rs.getBlob (...)' en lugar de 'rs.getBinaryStream (...)'. Nunca tarde para aprender JDBC. –

Respuesta

17

Mi conjetura es que ha confundido blobs de estilo OID y BYTEA. Los objetos binarios grandes se almacenan indirectamente con columnas OID en Postgres. Los datos reales del archivo se almacenan en algún lugar fuera de la tabla de la base de datos por Postgres. La columna solo contiene un identificador de objeto que está asociado internamente con el blob. Por ejemplo:

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) 

Si se utiliza el método ResultSet#getBlob(String), que se espera una columna de estilo OID. getBlob lee los datos de la columna y los convierte en Long. Luego intenta leer los datos binarios asociados de su almacenamiento interno.

Por otro lado, con BYTEA puede colocar pequeñas piezas de datos binarios directamente en su base de datos. Por ejemplo:

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) 

Aquí, la columna de datos contiene directamente los datos binarios. Si intenta utilizar getBlob en dicha columna, los datos todavía se interpretarán como OID, pero obviamente no cabrán en un Long. Vamos a probar esto en la base de datos, que acabamos de crear:

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"); 
===> [email protected] 
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() 
===> [email protected] 
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) 
     ... 
+0

¡Gracias! Así que rs.getBytes ("imagen") funcionó para mí para obtener el byteArray :-) – Bohne

Cuestiones relacionadas