Что касается использования хранимых процедур MySQL с транзакциями, и у меня возникает проблема с получением ошибки.
Проблема в том, что мне нужно установить exit_handler для отката транзакции, если что-то не получится. Но когда я это делаю, я не получаю никаких ошибок, если что-то пойдет не так. Например, если я случайно передаю значение NULL и попытаюсь вставить его в ненулевое поле.
Я использую возвращаемое значение, чтобы программно указать успех или неудачу, однако это ничего не говорит мне, что на самом деле пошло не так.
Я использую Perl DBI для общения с MySQL. Я использую MySQL 5.0.92 на рабочем сервере и MySQL 5.0.51a на сервере разработки. Переход на более новую версию MySQL политически несостоятелен.
Это упрощенный пример:
DELIMITER //
CREATE PROCEDURE pmt_new(
app_id varchar(40),
out ret tinyint unsigned,
out pmt_req_id int(10) unsigned)
BEGIN
DECLARE v_pmt_req_type int(10) unsigned;
DECLARE exit handler for not found, sqlwarning, sqlexception rollback;
set ret=1;
START TRANSACTION;
SELECT pmt_type INTO v_pmt_req_type FROM pmt_req_types WHERE pmt_req_name = 'Name 1';
INSERT INTO pmt_reqs (pmt_req_id, pmt_req_type, app_id)
values (null, v_pmt_req_type, app_id);
set pmt_req_id = last_insert_id();
INSERT INTO other (pmt_req_id) values (pmt_req_id);
COMMIT;
set ret=0;
END//
DELIMITER ;
Вместо того, чтобы просто выполнять откат в вашем обработчике выхода, вам нужно что-то вернуть...
В настоящее время у вас есть
DECLARE exit handler for not found, sqlwarning, sqlexception rollback;
Измените его на что-то вроде...
DECLARE exit handler for not found, sqlwarning, sqlexception
begin
rollback;
select "We had to rollback, error!";
end;
В 5.5 они добавили операторы SIGNAL/RESIGNAL, чтобы вы могли "возвратить" ошибку, но предыдущие версии вы должны отбросить свое собственное решение. Если вам нужно, вы можете объявить несколько обработчиков выходных данных, чтобы лучше адаптировать выход, или настроить собственную таблицу ошибок, из которой вы можете извлечь.
Вы также можете выполнить входное тестирование внутри хранимой процедуры. Хотите узнать, является ли app_id нулевым?
DELIMITER //
CREATE PROCEDURE pmt_new(
app_id varchar(40),
out result varchar(256),
out ret tinyint unsigned,
out pmt_req_id int(10) unsigned)
BEGIN
DECLARE v_pmt_req_type int(10) unsigned;
DECLARE exit handler for not found, sqlwarning, sqlexception rollback;
SET ret=1;
SET result = "";
IF app_id IS NULL THEN
set result = "Supplied ID is Null";
ELSE
START TRANSACTION;
SELECT pmt_type INTO v_pmt_req_type FROM pmt_req_types WHERE pmt_req_name = 'Name 1';
INSERT INTO pmt_reqs (pmt_req_id, pmt_req_type, app_id)
values (null, v_pmt_req_type, app_id);
set pmt_req_id = last_insert_id();
INSERT INTO other (pmt_req_id) values (pmt_req_id);
COMMIT;
set ret=0;
END IF;
END//
DELIMITER ;
Выполнение этого способа добавляет другой параметр, но дает вам гораздо лучшую информацию. Вы можете сделать то же самое с несколькими обработчиками выходных данных.