我有一个名为currentItem的字段,该字段有一个触发器,它调用存储过程(带事务)sp_TransferData来执行一些信息传输到工作表。如果存储过程失败 - 我想恢复currentItem的旧值 - 因为它没有有效地改变。
我正在使用MySQL,我希望这个逻辑能够在我的触发器中 - 显然我们不想要无限循环,所以我该如何实现呢?
触发伪代码:
Call sp_TransferData(@ResultCode);
Select @ResultCode into Result;
If Result < 0 THEN
thisField Value = OLD.Value;
End If;
//编辑 9-16-2016 13:00 // 这张表中只有一行,绝不是更多!为简洁起见编辑了列表。
table global_items
Id INT PK,
lsize INT,
wsize INT,
currentItem INT
触发器在currentItem上更新后或之前我不在乎哪个只要它工作并且不会重置触发器:
If the value has changed CALL sp_TransferData(@ResultCode);
If (SELECT @ResultCode) < 0 THEN
Reset currentItem to old value but do not cycle the trigger since we are only resetting it.
EndIf;
只是添加这个是我在触发器代码中的不正确之处。 提供了表定义。
BEGIN
IF NEW.currentItem <> OLD.currentItem THEN
call sp_CurrentItemChanged(NEW.currentItem, @ResultCode, @ResultMsg);
IF ((Select @ResultCode) < 0) THEN
NEW.currentItem = OLD.currentItem;
END IF;
END IF;
END
CREATE TABLE working_table (
Id int(11) NOT NULL AUTO_INCREMENT,
Mbf float DEFAULT NULL,
Width float DEFAULT NULL,
Pulse int(11) DEFAULT NULL,
PRIMARY KEY (Id)
)
ENGINE = INNODB
AUTO_INCREMENT = 1
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;
CREATE TABLE recipe (
Id int(11) NOT NULL AUTO_INCREMENT,
Name varchar(80) NOT NULL DEFAULT 'UnAssigned',
IsDefault tinyint(1) DEFAULT 0,
PRIMARY KEY (Id),
UNIQUE INDEX Id_UNIQUE (Id),
UNIQUE INDEX Name_UNIQUE (Name)
)
ENGINE = INNODB
AUTO_INCREMENT = 1
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;
CREATE TABLE Packs (
Id int(11) NOT NULL AUTO_INCREMENT,
Name varchar(45) NOT NULL DEFAULT 'UNDEFINED',
Width float NOT NULL DEFAULT 0,
Pulse int(11) NOT NULL DEFAULT 0,
Mbf float NOT NULL DEFAULT 0,
RecipeID int(11) NOT NULL DEFAULT 0,
SetupID int(11) DEFAULT 1,
PRIMARY KEY (Id),
INDEX SetupID_ndx (SetupID),
INDEX FK_PackRecipeID_Recipe_ID_idx (RecipeID),
INDEX FK_RecipeID_PackS_idx (RecipeID),
CONSTRAINT FK_PackRecipeID_Recipe_ID FOREIGN KEY (RecipeID)
REFERENCES recipe (Id) ON DELETE CASCADE ON UPDATE CASCADE
)
ENGINE = INNODB
AUTO_INCREMENT = 1
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;
CREATE TABLE global_items (
Id int(11) NOT NULL AUTO_INCREMENT,
PackSys_Count int(11) DEFAULT NULL,
Active_Recipe int(11) DEFAULT 1,
PRIMARY KEY (Id)
)
ENGINE = INNODB
AUTO_INCREMENT = 2
CHARACTER SET utf8
COLLATE utf8_general_ci
ROW_FORMAT = DYNAMIC;
当global_items.Active_recipe更改触发器时触发..移动的数据在包及其相关表(此处简称)中指向working_table。 global_items表永远不会被冗长的存储过程或任何其他触发器或任何其他sql代码中的任何内容触及。它永远不会被SQL存储内部的任何东西修改 - 只有外部应用程序才能触及它。我不确定如何在存储过程失败时将值恢复为原始值。
答案 0 :(得分:1)
我想我可能会理解你的目标。但是,既然你没有完全显示你的触发器,我猜,而不是存储过程,我只是飞过它并进行调查。
我认为问题在于你的存储过程没有OUT
限定符来使其可写。以下工作正常,我认为它抓住了如何解决您的问题。
架构:
-- drop table global_items;
create table global_items
( Id INT primary key,
lsize INT not null,
wsize INT not null,
currentItem INT not null,
theCount int not null
);
insert global_items(Id,lsize,wsize,currentItem,theCount) VALUES
(1,1,1,100,0);
select * from global_items;
触发:
DROP TRIGGER IF EXISTS giBeforeUpdate;
DELIMITER $$
CREATE TRIGGER giBeforeUpdate
BEFORE UPDATE
ON global_items FOR EACH ROW
BEGIN
DECLARE tRet INT;
SET tRet=0;
SET NEW.theCount=OLD.theCount+1;
CALL uspDoSomething7(tRet);
IF tRet=1 THEN
-- stored proc said FAILURE
SET NEW.currentItem=OLD.currentItem;
END IF;
END;$$
DELIMITER ;
存储过程:
DROP PROCEDURE IF EXISTS uspDoSomething7;
DELIMITER $$
CREATE PROCEDURE uspDoSomething7(OUT retVal INT)
BEGIN
DECLARE rndNum INT;
SET rndNum=FLOOR(RAND()*2)+1; -- random number 1 or 2
-- sets retVal to 1 on FAILURE
IF rndNum=2 THEN
SET retVal=1; -- FAIL
ELSE
SET retVal=0; -- SUCCESS
END IF;
END$$
DELIMITER ;
测试:
反复拨打此确认,大约一半的时间失败
即,currentItem保留其旧值
但每次点击currentItem=
部分的更新stmt
update global_items set currentItem=410,lsize=2 where Id=1;
select * from global_items;