Cercando di leggere un BLOB come un InputStream, ma sempre errore Connection Closed. Spring3 getJdbcTemplate()

Mi sto muovendo un’applicazione per utilizzare il Spring3 quadro e ho il codice che legge un BLOB colonna di un Database Oracle:

Funziona:

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

Ma quando cerco di scrivere con Molla con l’ 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();

Sto diventando un java.io.IOException: Closed Connection Eccezione.

Sto pensando che la Molla deve essere di chiudere la connessione per il InputStream prima di andare in giro per il processo. Vorrei che voi ragazzi avete un modo migliore di scrivere questo?

Edit: Alcuni più profondità al di Eccezione:

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 Replies
  1. 4

    Sì, Primavera, pulire e riordinare la connessione quando si lascia il query metodo.

    Soluzione più semplice è quello di eseguire il trattamento all’interno del RowMapper, ad esempio,

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

    Se si desidera solo di gestire la prima riga, quindi utilizzare un ResultSetExtractor invece di un RowMapper.

    • Ha un senso. E funziona. Grazie per il suggerimento sul ResultSetExtractor Po’.
  2. 0

    Altro (magari più semplici), un modo di prevenire i Primavera dalla chiusura, connessione prematuramente, è l’avvio di una transazione prima di eseguire la query.

    Questo può essere fatto in codice inserendo

    session.beginTransaction();

    Da qualche parte prima chiamata executeQuery.

    • Credo che può essere ottenuto anche con ‘@Transactional’ annotazione, ma non ho la prova, e probabilmente è anche auspicabile eseguire l’intero metodo in una transazione con l’unico scopo di ricevere un Blob di risultato. Inoltre, la transazione di annotazione funziona solo per metodo pubblico-chiamate, quindi potrebbe anche essere del tutto impraticabile in questa situazione.
  3. 0

    Come per ResultSet::getBinaryStream documentazione, il valore può essere letto in “blocchi”, che significa che se si chiude la connessione e quindi provare a leggere abbastanza byte dal torrente, solleva un’eccezione quando il blocco successivo è necessario, ma non possono essere restituiti dal database.

    Come alternativa, si può provare a leggere l’intero valore utilizzando il ResultSet::getBytes metodo, e poi convertire un InputStream se è necessario (istanziare un nuovo ByteArrayInputStream).

Lascia un commento