Обработка ошибок запроса в операторе транзакции MySQL

#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 утверждения (для чего они мне нужны) могут работать только внутри a BEGIN и END , и это разрешено только в определенных утверждениях, включая a PROCEDURE . Я попробовал это в MySQL Workbench, и это сработало.

2. Один вопрос… В своем TRANSACTION заявлении (не в примере) я использовал @@ROWCOUNT есть ли разница между этим и ROW_COUNT() ? Одно лучше другого? Или они одинаково хорошо делают одно и то же?

3. Я не знал, что ROWCOUNT доступен непосредственно в качестве системной переменной сеанса, и я не могу найти никакой документации, подтверждающей его использование. Я могу найти на него ссылку только как на свойство курсора. Я буду придерживаться использования функции так, как она есть в официальных документах.

4. Хорошо, спасибо. Это имеет смысл… может быть, мне тоже следует использовать функции вместо этого…