Как лаконично вызвать процедуру PL / SQL и вернуть ее выходные переменные в Spring с помощью JdbcTemplate? - PullRequest
0 голосов
/ 04 февраля 2020

Новый для Oracle здесь. Мой опыт заключается в создании веб-приложений, которые отправляют запросы в базу данных и возвращают «набор результатов», например, в Java с помощью Spring и JdbcTemplate.

Например, вот пример кода с обычным SQL query, используя класс RowMapper, чтобы превратить строки набора результатов в список Java:

public List<Widget> findAllWidgets() {
    return jdbcTemplate.query("SELECT * FROM widgets", new WidgetRowMapper());
}

Теперь мне поручено написать запрос, который вызывает хранимый PL / SQL процедура. Эта процедура имеет два входных аргумента (которые я могу обработать) и два выходных аргумента (назовем их error_code и error_message). Я хочу отправить запрос в базу данных, которая (а) запустит процедуру с моими входами и (б) вернет два вывода. Я был бы одинаково рад иметь два выхода в виде «строки» или просто связать их с двумя Java переменными.

Вот что я пробовал, и это не выдает ошибку, но не получает выходные значения, либо. Java переменные errorCode и errorMessage остаются пустыми строками:

public Map<String,String> callMyProcedure() {
    String errorCode="";
    String errorMessage="";
    jdbcTemplate.update("call myprocedure(?,?,?,?)","input1","input2",errorCode,errorMessage);
    return Map.of("errorCode",errorCode,"errorMessage",errorMessage);
}

Вопрос заключается в следующем: Как я могу получить значения переменных "OUT" процедуры PL / SQL при вызове процедуры из Java с помощью JdbcTemplate?

РЕДАКТИРОВАТЬ: я принял ответ Алекса, который не использует JdbcTemplate, потому что, кажется, это лучший способ. Мой собственный ответ использует JdbcTemplate, но требует гораздо больше кода, поэтому, если вы ищете что-то, что конкретно отвечает на вопрос, это будет сделано.

Ответы [ 3 ]

1 голос
/ 05 февраля 2020

Вы можете получить соединение в jdbcTemplate и получить выходные данные, используя методы get как getNString

try (Connection connection = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
CallableStatement statement = connection.prepareCall("{call myprocedure(?,?,?,?,?,?,?,?)}");
statement.execute();
statement.getNString(1); // using index or your parameter name

Извлекает значение указанного параметра NCHAR, NVARCHAR или LONGNVARCHAR в виде строки в языке программирования Java.

1 голос
/ 15 февраля 2020

Вы можете использовать обычный JDB C.

final String charlie;
final String zulu;
try (CallableStatement cs = connection.prepareCall("{call myprocedure(?,?,?,?,?,?,?,?)}")) {
    cs.setString(1, "foo");
    cs.setString(2, "bar");
    cs.setString(3, "baz");
    cs.setString(4, "whisky");
    cs.setString(5, "tango");
    cs.setString(6, "foxtrot");
    cs.registerOutParameter(7, Types.VARCHAR);
    cs.registerOutParameter(8, Types.VARCHAR);
    cs.execute();
    connection.commit(); // optional
    charlie = cs.getString(7);
    zulu = cs.getString(8);
}

. При использовании JDB C опасно использовать метод getInt и аналогичные, поскольку они преобразуют тип в примитив и ноль заменяется на 0. Лучше использовать (Integer) cs.getObject(). Точно так же setInt не поддерживает ссылочный тип.

0 голосов
/ 04 февраля 2020

Я нашел некоторые указания из старого вопроса здесь , и придумал это чудовище:

    public Map<String,Object> callMyProcedure() {
        return jdbcTemplate.call(new CallableStatementCreator() {
            @Override
            public CallableStatement createCallableStatement(Connection connection) throws SQLException {
                CallableStatement cs = connection.prepareCall("{call myprocedure(?,?,?,?,?,?,?,?)}");
                cs.setString(1,"foo");
                cs.setString(2,"bar");
                cs.setString(3,"baz");
                cs.setString(4,"whisky");
                cs.setString(5,"tango");
                cs.setString(6,"foxtrot");
                cs.registerOutParameter(7, Types.VARCHAR);
                cs.registerOutParameter(8, Types.VARCHAR);
                return cs;
            }
        },Arrays.asList(
                new SqlParameter(Types.VARCHAR),
                new SqlParameter(Types.VARCHAR),
                new SqlParameter(Types.VARCHAR),
                new SqlParameter(Types.VARCHAR),
                new SqlParameter(Types.VARCHAR),
                new SqlParameter(Types.VARCHAR),
                new SqlOutParameter("errorCode",Types.VARCHAR),
                new SqlOutParameter("errorMessage",Types.VARCHAR)
        ));
    }

Это работает , но я ищу за ответ, который может сделать то же самое более кратко. Может быть, Spring добавил новый интерфейс к JdbcTemplate за годы, прошедшие с того более старого ответа?

...