数据库触发器对于跨表完整性约束是不是安全?
Posted
技术标签:
【中文标题】数据库触发器对于跨表完整性约束是不是安全?【英文标题】:Are database triggers safe for cross table integrity constraints?数据库触发器对于跨表完整性约束是否安全? 【发布时间】:2013-06-02 08:23:33 【问题描述】:我建议使用触发器来检查回答this question 的交叉表完整性约束。在 cmets 中已经提示它可能会导致问题:
执行跨行检查的触发器很少在大多数数据库上工作......因为它们无法从其他事务中读取未提交的行
不过,我还没有找到任何支持该声明的来源。 Official documentation 没有提及任何内容。我发现的其他问题已涵盖here on SO - 它主要批评潜在的隐藏复杂性,因为第一眼看不到触发器。但即使是highest rated answer 也承认它们用于完整性问题。
所以我的问题是:数据库触发器对于跨表完整性约束是否安全?具体来说,下面的解决方案是否可行?
总结原始问题。我们有桌子
玩家 - 玩家 ID、玩家名称 投注 - BetID、BetName plays_in - BetID、PlayerID约束是 BetName 和 PlayerID 的组合应该是唯一的。建议触发器的定义:
CREATE TRIGGER check_bet_name BEFORE INSERT ON plays_in
FOR EACH ROW BEGIN
DECLARE bet_exists INT DEFAULT 0;
DECLARE msg VARCHAR(255);
SELECT 1 INTO bet_exists
FROM Bet AS b1
WHERE b1.BetID = NEW.BetID
AND EXISTS (SELECT *
FROM plays_in AS p JOIN Bet AS b2 USING (BetID)
WHERE p.PlayerID = NEW.PlayerID AND b2.BetName = b1.BetName
)
LIMIT 1;
IF bet_exists THEN
SET msg = "Bet name already exists...";
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
END IF;
END//
【问题讨论】:
你能否运行一个简单的测试来检查关于无法看到未提交更改的声明(听起来应该是真的)? @Thilo 哦,天哪,你说得对,它真的失败了 【参考方案1】:答案是触发器不安全。
事实证明,触发器确实没有看到其他事务中未提交的更改,并且没有错误地通过。可以这样演示
交易1:
START TRANSACTION;
INSERT INTO plays_in (BetID, PlayerID) VALUES (1,1); -- query A
事务 2:
START TRANSACTION;
INSERT INTO plays_in (BetID, PlayerID) VALUES (1,2); -- query B; in conflict with A, but passses
两笔交易:
COMMIT;
现在plays_in
将包含两个插入的记录,即使 A 和 B 在单个事务中执行,触发器也会抛出错误。
全部示例源码可以在here获取
【讨论】:
【参考方案2】:这可能取决于哪个数据库以及您编写逻辑的程度。
早期版本的 infomodeler/visiomodeler 支持一些相当神秘和复杂的参照完整性形式,并提供了在多个数据库上实现它们的代码。 Sybase / sql server 的早期版本不支持声明性引用完整性,因此所有逻辑都在触发器中实现 - 成功。
我不会将反例的一个实现的失败视为权威。
【讨论】:
以上是关于数据库触发器对于跨表完整性约束是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章