Oracle上的Spring SimpleJdbcCall存储过程:Closed Connection访问BLOB输出参数

时间:2015-01-22 21:53:28

标签: java spring oracle jdbc

我试图使用Spring的SimpleJdbcCall从Oracle11gR2中的存储过程的输出参数中读取BLOB。但是,当我调用获取BLOB的长度以获取字节数组时,我收到以下错误:

java.sql.SQLRecoverableException: Closed Connection
at oracle.sql.BLOB.getDBAccess(BLOB.java:1122) ~[ojdbc6-11.2.0.4.0.jar:11.2.0.4.0]
at oracle.sql.BLOB.length(BLOB.java:156) ~[ojdbc6-11.2.0.4.0.jar:11.2.0.4.0]

这是我的存储过程(更改名称以保护无辜者):

FUNCTION my_stored_proc(in_param_1 IN VARCHAR2, in_param_2 IN VARCHAR2, out_param_1 OUT VARCHAR2, out_param_2 OUT VARCHAR2, out_param_3 OUT BLOB) 
  RETURN REF CURSOR
IS
  ...

这是我的Java代码(或至少是合理的传真):

SqlParameter[] parameters = {
    getResultParameter(getRowMapper()),
    new SqlParameter("in_param_1", Types.VARCHAR),
    new SqlParameter("in_param_2", Types.VARCHAR),
    new SqlOutParameter("out_param_1", Types.VARCHAR),
    new SqlOutParameter("out_param_2", Types.VARCHAR),
    new SqlOutParameter("out_param_3", Types.BLOB)
};

simpleJdbcCall = new SimpleJdbcCall(getDataSource());
simpleJdbcCall.setFunction(getResultIsCursor());
simpleJdbcCall.setProcedureName("my_stored_proc");
simpleJdbcCall.withoutProcedureColumnMetaDataAccess().declareParameters(parameters);

MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("in_param_1", requestId);
params.addValue("in_param_2", compositionId);

Map<String, Object> result = simpleJdbcCall.execute(params);

_errorMessage = (String)result.get("out_param_1");
_account = (String)result.get("out_param_2");

Blob blob = (Blob)result.get("out_param_3");
if (null != blob) {
    final byte[] data = blob.getBytes(1, (int) blob.length());
    ...
}

(据我所知,拥有输出参数并且返回参考光标的存储过程可能不是设计最好的存储过程,但是重构这是解开一件非常大的毛衣的开始范围现在。 此外,将Blob数据作为字节数组存储在内存中是可以的,因为存储的文件的大小上限非常小。)

如果可能的话,我想坚持使用SimpleJdbcCall,因为它是我正在使用的框架的基石。看起来好像LobHandler会解决这个问题,但是我还没有找到关于如何使用SimpleJdbcCall和out参数(只是ResultSets)的任何参考。

1 个答案:

答案 0 :(得分:1)

我用以下方法解决了这个问题:

  

SimpleJdbcCall fObtenerDocumentoBinario = new SimpleJdbcCall(jdbcTemplate).withSchemaName(Constantes.SCHEMA)                               .withCatalogName(Constantes.CATALOG)                               .withFunctionName(Constantes.F_RECUPERA_BLOB_DOCUMENTO);

     

fObtenerDocumentoBinario.addDeclaredParameter(new SqlOutParameter(&#34; P_DOCUMENTO&#34;,OracleTypes.BLOB,                               &#34; BLOB&#34;,新DocumentoBinarioSqlReturnType()));

DocumentoBinarioSqlReturnType定义为:

private class DocumentoBinarioSqlReturnType implements SqlReturnType {

    /**
     * M&eacute;todo sobrescrito getTypeValue.<br>
     * @param cs
     * @param paramIndex
     * @param sqlType
     * @param typeName
     * @return
     * @throws SQLException
     * @see org.springframework.jdbc.core.SqlReturnType#getTypeValue(java.sql.CallableStatement, int, int,
     *      java.lang.String)
     */
    public Object getTypeValue(CallableStatement cs, int paramIndex, int sqlType, String typeName)
                    throws SQLException {

        String pathname = Constantes.getTempDir() + System.currentTimeMillis() + Constantes.EXTENSION_PDF;

        InputStream inStream = null;
        try {

            inStream = cs.getBlob(3).getBinaryStream();

            UtilidadesIO.inputStreamToFile(inStream, pathname);

        } catch (SQLException e) {

            LOGGER.error("Error obteniendo el documento, comprobar en BBDD", e);
            throw e;

        } finally {
            if (null != inStream) {
                try {
                    inStream.close();
                } catch (IOException e) {

                    LOGGER.error(e.getMessage(), e);
                    inStream = null;
                }
            }
        }


        return pathname;

    }