Ошибка запроса на обновление java DAO

Я пытаюсь написать метод DAO для обновления значения в таблице postgres "accounts" всего с двумя столбцами: "id" string "balance" int

public Account setAccountBalance(String id, Integer balance) {
    Handle h = dbi.open();

    try{
        return h.createQuery("UPDATE accounts SET balance=" + balance.intValue() +
                            " WHERE id=\'" + id +"\';")
                .mapTo(Account.class)
                .first();
    } finally {
        h.close();
    }
}

Но при выполнении я вижу следующее исключение: org.skife.jdbi.v2.exceptions.NoResultsException: Query не имеет набора результатов, возможно, вы имели в виду обновление? [утверждение: «ОБНОВЛЕНИЕ баланса счетов SET = 20, ГДЕ id = '1';», расположенное: «ОБНОВЛЕНИЕ баланса счетов SET = 20, ГДЕ id = '1';», переписано: «ОБНОВЛЕНИЕ баланса счетов SET = 20, ГДЕ id = ' 1';", аргументы: { позиционный: {}, именованный: {id: '1'}, искатель: []}]

Любая идея, если проблема в синтаксисе запроса или использовании DAO?


person vic    schedule 30.12.2017    source источник
comment
Вы можете попробовать удалить точку с запятой из строки запроса. И вам определенно следует использовать подготовленные операторы вместо объединения строк параметров запроса.   -  person Mick Mnemonic    schedule 30.12.2017
comment
Кроме того, у вас есть UPDATE SQL, который обычно (в зависимости от драйвера JDBC) не имеет набора результатов. Вероятно, вы используете неправильный метод API (createQuery()) для обновления.   -  person Mick Mnemonic    schedule 30.12.2017
comment
Также узнайте о подготовленных заявлениях. Ваш код уязвим для SQL-инъекций и не сработает, если идентификатор содержит цитату.   -  person JB Nizet    schedule 30.12.2017
comment
Вероятно, вы используете неправильный метод API (createQuery()) для обновления. – Мик Мнемоник В этом есть смысл... Какой метод мне следует использовать?   -  person vic    schedule 30.12.2017
comment
Понятия не имею, потому что я не знаю API, который вы используете. Быстрый Google предлагает JDBI, и есть execute() метод, который, вероятно, работает. По ссылке есть примеры подготовленных операторов (вопросительные знаки в SQL), поэтому вы также можете переключиться на их использование.   -  person Mick Mnemonic    schedule 30.12.2017


Ответы (1)


Похоже, вы используете JDBI. Согласно документации, SQL UPDATE можно выполнять через Handle.execute() следующим образом:

h.execute("UPDATE accounts SET balance=? WHERE id=?", balance.intValue(), id);

Но метод execute не возвращает набор результатов и поэтому не может использоваться для создания объекта Account. Для этого вам нужно будет создать отдельный запрос, может быть, что-то вроде

return h.createQuery("SELECT id, balance FROM accounts WHERE id = :id")
            .bind("id", id)
            .mapTo(Account.class)
            .first();
person Mick Mnemonic    schedule 30.12.2017
comment
Будет ли это работать в случае нескольких клиентов и одной базы данных? - person vic; 31.12.2017
comment
Да, но если вы будете строить, например. реального банковского приложения, вам необходимо рассмотреть более широкую картину транзакций и уровни изоляции. Например, установка баланса учетной записи должна быть операцией, предотвращающей одновременное изменение одной и той же учетной записи другими клиентами. Один из способов добиться этого — получить блокировку строки таблицы перед обновлением, например через предложение SELECT FOR UPDATE SQL. Но эта тема выходит за рамки вашего первоначального вопроса. - person Mick Mnemonic; 01.01.2018