Как проверить, правильно ли был выполнен предыдущий запрос?

#php #mysql #sql #transactions

Вопрос:

Я должен уменьшить деньги со счета пользователя и увеличить другой счет пользователя, а именно перевести деньги со счета на другой. У меня есть этот код, например, в MySQL:

 START TRANSACTION;
UPDATE accounts
SET balance = (balance-100)
WHERE account_id = 2 AND balance>100;

--If the above query is succesfully then:
UPDATE accounts
SET balance = (balance 100)
WHERE account_id =1;

--How can I exec the commit only if everything is ok?
COMMIT;
 

Первый запрос выполняется только в том случае, если баланс>100.

Однако второй запрос (а именно второе обновление) следует выполнять только в том случае, если предыдущий запрос уменьшил баланс. Как я мог автоматически проверить это?

Кроме того, ФИКСАЦИЯ; должна выполняться только в том случае, если предыдущие 2 запроса выполнили свою работу.

Как это может быть реализовано?

(Я тоже использую PHP, но я думаю, что эту проблему можно легко решить с помощью sql. Я ошибаюсь?)

Комментарии:

1. Определите соответствующий ОБРАБОТЧИК ПРОДОЛЖЕНИЯ , установите некоторую переменную флага в своем коде, проанализируйте ее значение после выполнения инструкции, если предыдущая инструкция(инструкции) выдала какую-либо ошибку/предупреждение. Не забудьте удалить WHERE из 1-го запроса, но добавьте CHECK (balance >= 0) ограничение в определение таблицы, которое позволяет обнаружить проблему.

2. Первый запрос выполняется только в том случае, если баланс>100.> Это неправильно !!! запрос выполняется в любом случае. Он изменяет данные только при выполнении условия — это верно.

3. @Akina, Конечно, я имел в виду, что изменение выполняется только в том случае, если баланс>100

Ответ №1:

Выполните операцию как отдельный запрос, а не как пакет запросов:

 UPDATE accounts t1
CROSS JOIN accounts t2
SET t1.balance = (t1.balance-100),
    t2.balance = (t2.balance 100)
WHERE t1.account_id = 2 AND t1.balance>100
  AND t2.balance_id = 1;

-- or

UPDATE accounts
SET balance = balance   CASE account_id WHEN 1 THEN 100
                                        WHEN 2 THEN -100 END
WHERE account_id IN (1,2);
 

И вам вообще не нужно участвовать в транзакции.


Также вы можете проверить количество строк, измененных (фактически, на диске, а не формально) предыдущим запросом, и учесть эту информацию во 2-м запросе:

 START TRANSACTION;

UPDATE accounts
SET balance = (balance-100)
WHERE account_id = 2 AND balance>100;

UPDATE accounts
SET balance = (balance 100)
WHERE account_id =1 
  AND ROW_COUNT();  -- check does a row was altered in previous statement
                    -- if not then this statement will not alter any row too

COMMIT;
 

Комментарии:

1. А что, если произойдет сбой при выполнении первого предложения set? Вся операция свернута?

2. @Umbert В 1 — м варианте (в обоих вариантах) — если запрос не будет выполнен по какой-либо причине, ни одна строка не будет обновлена. Запрос не может обновить только одну строку из двух сопоставленных строк — либо все, либо ни одной.

3. Таким образом, больше предложений набора в ОБНОВЛЕНИИ все выполнено или нет, то есть у них есть своего рода встроенный переход. Кроме того, перекрестное соединение (декартово произведение) в вашем первом решении необходимо для того, чтобы иметь возможность ссылаться на обе таблицы в НАБОРЕ?

4. @Umbert Один запрос-ЭТО ВСЕГДА транзакция. Исключение — макрофункции потока (например, ЗАГРУЗКА ДАННЫХ).