#mysql #sqltransaction
#mysql #sqlтранзакция
Вопрос:
Я прохожу курс проектирования и разработки баз данных и только что узнал о транзакциях SQL. Учебник (Изучение SQL 3-е издание Алана Болье) действительно хорошо объясняет, как все работает, но не очень хорошо дает примеры фактического кода, который нам нужно было бы использовать.
В учебнике практически единственное место, где говорится об обработке ошибок в транзакции, — это пример инструкции транзакции, но только в псевдокоде:
START TRANSACTION; /* withdraw money from first account, making sure balance is sufficient */ UPDATE account SET avail_balance = avail_balance - 500 WHERE account_id = 9988 AND avail_balance gt; 500; IF lt;exactly one row was updated by the previous statementgt; THEN /* deposit money into second account */ UPDATE account SET avail_balance = avail_balance 500 WHERE account_id = 9989; IF lt;exactly one row was updated by the previous statementgt; THEN /* everything worked, make the changes permanent */ COMMIT; ELSE /* something went wrong, undo all changes in this transaction */ ROLLBACK; END IF; ELSE /* insufficient funds, or error encountered during update */ ROLLBACK; END IF;
В MySQL workbench (программное обеспечение, которое мы используем для тестирования наших запросов) я попытался использовать CASE
оператор вместо IF
(поскольку MySQL использует CASE
вместо IF
), но это выдало бы мне ошибку, в которой говорится:
«СЛУЧАЙ» недействителен в этой позиции, ожидая EOF, ALTER…
Я попытался посмотреть, как это сделать, но все, что я нашел, было либо не для MySQL (базы данных Oracle или Microsoft SQL Server), либо было так же (не) полезно, как в учебнике…
Любая помощь будет признательна!
Ответ №1:
То, как вы управляете потоком, будет зависеть от клиента, поэтому примеры из учебников, которые у вас есть, находятся в псевдокоде. Я не думаю, что есть какой-либо способ управлять потоком в SQL-скриптах на вкладках запросов MySQL Workbench, но я могу ошибаться.
Вы, конечно, могли бы создать хранимую процедуру для инкапсуляции примера транзакции, указанного в вашем исходном сообщении —
CREATE PROCEDURE `sp_TransferFunds`( IN amount DECIMAL(12,2), IN sendingAccount INTEGER, IN receivingAccount INTEGER ) sp:BEGIN /* do some validation of the input parameters */ IF amount lt;= 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Amount to be transferred must be greater than zero'; LEAVE sp; ELSEIF sendingAccount = receivingAccount THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Sending and receiving accounts must be different'; LEAVE sp; END IF; START TRANSACTION; /* withdraw money from first account, making sure balance is sufficient */ UPDATE account SET avail_balance = avail_balance - amount WHERE account_id = sendingAccount AND avail_balance gt;= amount; SET @tx1 = ROW_COUNT(); IF (@tx1 = 1) THEN /* deposit money into second account */ UPDATE account SET avail_balance = avail_balance amount WHERE account_id = receivingAccount; SET @tx2 = ROW_COUNT(); IF (@tx2 = 1) THEN /* everything worked, make the changes permanent */ COMMIT; ELSE /* something went wrong, undo all changes in this transaction */ ROLLBACK; SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Something went wrong!'; END IF; ELSE /* insufficient funds, or error encountered during update */ ROLLBACK; SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Insufficient funds in sendingAccount!'; END IF; END
Если это бесполезно и у вас есть более конкретный пример того, чего вы пытаетесь достичь, пожалуйста, обновите свой исходный пост.
Комментарии:
1. Это очень полезно, спасибо! В конце концов я нашел кое-что , в чем говорилось о том, как
CASE
утверждения (для чего они мне нужны) могут работать только внутри aBEGIN
иEND
, и это разрешено только в определенных утверждениях, включая aPROCEDURE
. Я попробовал это в MySQL Workbench, и это сработало.2. Один вопрос… В своем
TRANSACTION
заявлении (не в примере) я использовал@@ROWCOUNT
есть ли разница между этим иROW_COUNT()
? Одно лучше другого? Или они одинаково хорошо делают одно и то же?3. Я не знал, что ROWCOUNT доступен непосредственно в качестве системной переменной сеанса, и я не могу найти никакой документации, подтверждающей его использование. Я могу найти на него ссылку только как на свойство курсора. Я буду придерживаться использования функции так, как она есть в официальных документах.
4. Хорошо, спасибо. Это имеет смысл… может быть, мне тоже следует использовать функции вместо этого…