Попытка прочитать BLOB-объект как InputStream, но при этом возникает ошибка Connection Closed.Spring3 getJdbcTemplate () - PullRequest
3 голосов
/ 23 марта 2012

Я перемещаю приложение для использования среды Spring3, и у меня есть код, который читает столбец BLOB из базы данных Oracle:

Это работает:

        String fileSqlStr =
                "select file_id, file_content from cpm_file where file_id = 4";
        PreparedStatement ps = conn.prepareStatement(fileSqlStr);
        ResultSet rs = ps.executeQuery();
        rs.next();
        int fileId = rs.getInt("file_id");
        InputStream fis = rs.getBinaryStream("file_content");
        ExlBOMImporter ei = new ExlBOMImporter(fis);

Но когдаЯ пытаюсь написать его с помощью Spring, используя JdbcTemplate bean:

 InputStream is = getJdbcTemplate().query(getFileContentSql, new RowMapper<InputStream>() {

                public InputStream mapRow(ResultSet rs, int rowNum) throws SQLException {
                    OracleLobHandler lobHandler = new OracleLobHandler();
                    return lobHandler.getBlobAsBinaryStream(rs, "file_content");
                }
            }, fileId).get(0);
 ExlImporter importer = new ExlBOMImporter(is);
 importer.process();

Я получаю java.io.IOException: Closed Connection Exception.

Я думаю, что Spring должен закрывать соединение дляInputStream прежде чем я найду время, чтобы обработать его.Ребята, вы бы могли лучше написать это?

Редактировать: Еще немного глубины исключения:

java.io.IOException: Closed Connection
        at oracle.jdbc.driver.OracleBlobInputStream.needBytes(OracleBlobInputStream.java:204)
        at oracle.jdbc.driver.OracleBufferedStream.readInternal(OracleBufferedStream.java:169)
        at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:143)
        at org.apache.poi.util.IOUtils.readFully(IOUtils.java:92)
        at org.apache.poi.util.IOUtils.readFully(IOUtils.java:77)
        at oracle.jdbc.driver.OracleBlobInputStream.needBytes(OracleBlobInputStream.java:204)

Ответы [ 3 ]

4 голосов
/ 23 марта 2012

Да, Spring исправит соединение, когда выйдет из метода query.

Самое простое решение - выполнить обработку внутри RowMapper, например,

getJdbcTemplate().query(getFileContentSql, new RowMapper<Void>() {
    public void mapRow(ResultSet rs, int rowNum) throws SQLException {
        OracleLobHandler lobHandler = new OracleLobHandler();
        InputStream inputStream = lobHandler.getBlobAsBinaryStream(rs, "file_content");
        ExlImporter importer = new ExlBOMImporter(inputStream);
        importer.process();
    }
}, fileId);

Если вы хотите обработать только первый ряд, используйте ResultSetExtractor вместо RowMapper.

0 голосов
/ 12 июля 2016

Согласно документации ResultSet::getBinaryStream значение можно прочитать в «чанках», это означает, что если вы закроете соединение, а затем попытаетесь прочитать достаточно байтов из потока, это вызовет исключение, когда потребуется следующий чанк.но не может быть возвращено из базы данных.

В качестве альтернативы вы можете попробовать прочитать все значение с помощью метода ResultSet::getBytes, а затем преобразовать его в InputStream, если вам нужно (создание нового ByteArrayInputStream).

0 голосов
/ 07 июня 2016

Другой (возможно, более простой) способ предотвратить преждевременное закрытие соединения Spring - это запустить транзакцию перед выполнением запроса.

Это можно сделать в коде, вставив

session.beginTransaction();

Где-то перед вызовом executeQuery.

...