У меня есть хранимая процедура, где я хотел бы откат на случай, если что-то пойдет не так. Для этого я использую EXIT HANDLER, например:
DECLARE EXIT HANDLER FOR sqlexception
begin
ROLLBACK;
end;
Но таким образом, когда я вызываю эту хранимую процедуру, в случае каких-либо ошибок, хранимая процедура завершается успешно, и я не знаю, в чем была реальная проблема. Я хочу, чтобы клиент (php) зарегистрировал ошибку, чтобы устранить ее. Поэтому я изменяю таким образом:
DECLARE EXIT HANDLER FOR sqlexception
begin
get diagnostics condition 1
@p1 = MESSAGE_TEXT;
ROLLBACK;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @p1;
end;
Так что теперь хранимые процедуры отката и бросают исключение, что обработчик перехватил. Это круто, но иногда MESSAGE_TEXT составляет более 128 символов, и в таких случаях я получаю:
Код ошибки: 1648. Слишком длинные данные для элемента условия ‘MESSAGE_TEXT’
Конечно это решение не приемлемо:
DECLARE EXIT HANDLER FOR sqlexception
begin
get diagnostics condition 1
@p1 = MESSAGE_TEXT;
ROLLBACK;
SET @p1=SUBSTRING(@p1,1,128);
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @p1;
end;
Есть ли способ перехватить какое-либо исключение, выполнить откат и затем выдать это же исключение клиенту?
Большое спасибо за вашу помощь
Как предположил Кенни, ответ таков:
DECLARE EXIT HANDLER FOR sqlexception
begin
ROLLBACK;
RESIGNAL;
end;
Я использую этот шаблон, и он работает для меня. Когда встречаются исключения, поток транзакций немедленно переходит к DECLARE EXIT HANDLER FOR SQLEXCEPTION
, Последний оператор, который будет выполнен движком MySQL, будет ROLLBACK
, После этого поток транзакций выходит из tblock
Обработайте исключения изящно, возвращая коды ошибок а также сообщение как набор записей (не выдавая ошибку в PHP), который ваш код PHP может легко манипулировать и отображать.
DELIMITER $$
CREATE PROCEDURE `ProcName`( <parameters here> )
BEGIN
START TRANSACTION;
tblock: BEGIN # start: transaction block
/* catch any exceptions, then rollback */
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@state = RETURNED_SQLSTATE,
@rtc = MYSQL_ERRNO,
@rmg = MESSAGE_TEXT; -- MySQL 5.6 > : comment diagnostics for lower versions
ROLLBACK;
END;
/* table transactions here */
COMMIT;
END tblock; # end: transaction block
SELECT @rtc AS retcode,
@rmg AS retmsg,
'some ret value' AS retval;
END$$
DELIMITER ;
В SQL, как обычно, 0 — это успех, а ненулевые (обычно больше нуля) значения указывают на ошибку. Вы можете хотеть следовать за этим и сделать это практикой.