Подтвердить что ты не робот

Postgresql, JDBC и потоковые BLOB

Я пытаюсь извлечь blob из базы данных postgres, используя драйверы jdbc. Он слишком велик, чтобы иметь в памяти, поэтому я хочу передать его как загрузку. Я попытался использовать метод getBinaryStream на ResultSet, но выясняется, что этот метод действительно читает все это в памяти, поэтому не работает для большого файла.

По-видимому, можно использовать метод 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" - это содержимое файла. Вы можете себе представить, что это довольно длительное время, но на самом деле это не так.

Я застрял здесь. Кто-нибудь есть идеи о том, что происходит? Черт, я даже возьму альтернативные методы для потоковой передачи больших капель в качестве загрузки.

4b9b3361

Ответ 1

Моя догадка заключается в том, что вы смешались с блоками OID и BYTEA. Большие двоичные объекты хранятся косвенно с столбцами OID в Postgres. Фактические данные файла хранятся где-то за пределами таблицы базы данных Postgres. В столбце содержится только идентификатор объекта, связанный внутри с блобом. Например:

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");
===> [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)
        ...

Ответ 2

Помогли ли документы PostgreSQL для "Сохранения двоичных данных"?

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

Может оказаться полезным раздел под названием "Получение изображения из Большого объекта", который находится внизу страницы.