Вставьте byte[] в поле blob с помощью jdbcTemplate spring и хранимой процедуры

Я пытаюсь вставить byte[] в поле blob с хранимой процедурой и получаю исключение:

Ошибка обработки запроса; вложенным исключением является org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; неверная грамматика SQL [SELECT ID FROM sp_NEWFILE(?,?,?)]; вложенным исключением является org.firebirdsql.jdbc.field.TypeConversionException: ошибка преобразования в объект.

Модель:

public class fileBody { 
private int ID;
private byte[] BODY;
private String FILENAME; //getters an setters}

Вставьте его в базу данных

public class FileBodyDaoImpl implements FileBodyDao {

public int insertData(final FileBody fileBody) throws IOException {     
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    LobHandler lobHandler = new DefaultLobHandler();        
    final InputStream in = new ByteArrayInputStream(fileBody.getBODY());
    final int fileSize = in.available();
    Map<String, Object> out = jdbcTemplate.queryForMap("SELECT ID FROM  sp_NEWFILE(?,?,?)",
            new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
                protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException,
                        DataAccessException {
                    ps.setString(1, fileBody.getFILENAME());
                    lobCreator.setBlobAsBinaryStream(ps, 2, in, fileSize);
                    ps.setNull(3, java.sql.Types.INTEGER);
                }
            });     
    int last_inserted = Integer.parseInt(String.valueOf(out.get("ID")));
    return last_inserted;
}

И моя хранимая процедура

create or alter procedure sp_NEWFILE (
FILENAME varchar(255),
BODY blob sub_type 0 segment size 80,
USEID integer)
returns (
ID integer)
as
begin
  if (useid is not null) then ID=USEID;
  else ID=GEN_ID(gen_filebody_id,1);
  if ((FILENAME is NULL) or (FILENAME=''))  then FILENAME='UNDEFINED';
  INSERT INTO  t_filebody(ID,BODY,FILENAME) VALUES(:ID,:BODY,:FILENAME);
  suspend;
end^

и я получаю исключение:

Request processing failed; nested exception is org.springframework.jdbc.BadSqlGrammarException: 
PreparedStatementCallback; 
bad SQL grammar [SELECT ID FROM sp_NEWFILE(?,?,?)]; nested exception is org.firebirdsql.jdbc.field.TypeConversionException: Error converting to object.

Версии: jaybird-jdk17-2.2.5; Источник: firebird2.5 Версия: 2.5.1.26351.ds4-2ubuntu0.1;


person zond    schedule 01.09.2014    source источник
comment
Не могли бы вы включить полную трассировку стека и указать версию Jaybird и Firebird, которую вы используете?   -  person Mark Rotteveel    schedule 01.09.2014


Ответы (1)


Проблема в том, что queryForMap не поддерживает PreparedStatementCallback (в отличие, например, от execute), вместо этого ваш анонимный объект считается обычным параметром для выполнения запроса, и Jaybird не поддерживает этот тип объекта. И если бы Jaybird его поддерживал, вы бы получили ошибку из-за отсутствия параметров 2 и 3.

Ваш код можно значительно упростить, передав массив байтов:

Map<String, Object> out = jdbcTemplate.queryForMap("SELECT ID FROM sp_NEWFILE(?,?,?)",
        fileBody.getFILENAME(), fileBody.getBODY(), null);

Это работает, поскольку Jaybird рассматривает BLOB SUB_TYPE 0 как java.sql.Types.LONGVARBINARY, а приложение B JDBC 4.2 объявляет, что byte[] является типом по умолчанию для этого (хотя вы также можете использовать его как java.sql.Types.BLOB).

В качестве примечания: вашу хранимую процедуру не нужно выбирать (удаление SUSPEND делает ее исполняемой), и процедура также может быть заменена с помощью TRIGGER для создания первичного ключа и получения значения с помощью INSERT .. RETURNING .. или с помощью средства создания ключей JDBC (которое, в свою очередь, реализовано в Jaybird через INSERT .. RETURNING ..).

person Mark Rotteveel    schedule 01.09.2014