Хранимая процедура с транзакцией

Общая структура процедуры


DELIMITER $$

CREATE PROCEDURE имя_процедуры (
    IN параметр1 ТИП,
    IN параметр2 ТИП,
    ...
)
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        RESIGNAL;
    END;

    START TRANSACTION;

    -- Проверки, вставки, обновления

    COMMIT;
END$$

DELIMITER ;
        

Пример процедуры


DELIMITER $$

CREATE PROCEDURE оформить_продажу(
    IN p_id_dog INT,
    IN p_id_cli INT,
    IN p_cost DECIMAL(10,2)
)
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        RESIGNAL;
    END;

    START TRANSACTION;

    IF NOT EXISTS (SELECT 1 FROM dog WHERE id_dog = p_id_dog) THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Питомец не найден';
    END IF;

    IF NOT EXISTS (SELECT 1 FROM clients WHERE id_cli = p_id_cli) THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Клиент не найден';
    END IF;

    INSERT INTO orders (date_ord, status_order, cost, id_dog, id_cli)
    VALUES (CURDATE(), 'в пути', p_cost, p_id_dog, p_id_cli);

    COMMIT;
END$$

DELIMITER ;
        

Как вызвать процедуру

Пример:

CALL оформить_продажу(2, 1, 3000.00);
  • p_id_dog = 2: ID питомца
  • p_id_cli = 1: ID клиента
  • p_cost = 3000.00: Стоимость заказа

Объяснение ключевых частей

  1. DECLARE EXIT HANDLER FOR SQLEXCEPTION

    Откатывает транзакцию при ошибке. Используйте:

    ROLLBACK; RESIGNAL;
  2. START TRANSACTION и COMMIT

    Гарантирует атомарность — либо всё выполняется, либо ничего:

    
    START TRANSACTION;
    INSERT INTO orders (...) VALUES (...);
    UPDATE dog SET status = 'продан' WHERE id_dog = ...;
    COMMIT;
              
  3. IF NOT EXISTS

    Проверяет существование данных:

    
    IF NOT EXISTS (SELECT 1 FROM dog WHERE id_dog = p_id_dog) THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Питомец не найден';
    END IF;
              
  4. SIGNAL SQLSTATE '45000'

    Выбрасывает пользовательское исключение:

    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Питомец не найден';
  5. CURDATE()

    Устанавливает текущую дату:

    VALUES (CURDATE(), 'в пути', p_cost, p_id_dog, p_id_cli);

Частые ошибки и решения

Ошибка Причина Решение
Error 1452 id_dog или id_cli отсутствует Проверьте существование питомца и клиента
Error 1062 Дублирование id_ord Используйте автоинкремент для id_ord
Error 1338 Некорректный синтаксис Проверьте DELIMITER $$ и закрытие END$$

Как тестировать процедуру

  1. Успешный вызов:
    CALL оформить_продажу(2, 1, 3000.00);

    Проверьте таблицу orders: должен появиться новый заказ.

  2. Ошибка: питомец не найден
    CALL оформить_продажу(999, 1, 3000.00);

    Должна вылететь ошибка: "Питомец не найден".

  3. Ошибка: клиент не найден
    CALL оформить_продажу(2, 999, 3000.00);

    Должна вылететь ошибка: "Клиент не найден".

Общий шаблон для любого варианта


DELIMITER $$

CREATE PROCEDURE имя_процедуры (
    IN параметр1 ТИП,
    IN параметр2 ТИП,
    ...
)
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        RESIGNAL;
    END;

    START TRANSACTION;

    IF NOT EXISTS (SELECT 1 FROM таблица WHERE условие) THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Ошибка';
    END IF;

    INSERT INTO orders (...) VALUES (...);

    COMMIT;
END$$

DELIMITER ;
        
Создатель сайта не утверждает,
что данная шпаргалка действительно верная
Получить помощь