我分析了一个休眠生成的 oracle 数据库,发现从单个表中删除一行将触发 1200 多个触发器,以便删除子表中的相关行。触发器都是自动生成的 - 自动删除子行而不先检查是否存在。由于无法预测哪些子表实际上将具有相关行,因此我认为防止触发级联删除向下深入分支完全空肢体的可行解决方案是在尝试之前检查相关行是否存在删除。在其他 dbms 中,我可以在删除之前简单地声明“如果存在......”。在 oracle 中是否有类似的方法可以做到这一点?
4 回答
“从单个表中删除一行将触发 1200 多个触发器”这些语句或行级触发器是什么?如果是后者,它们只会在删除一行时触发。假设您在客户上有一个 BEFORE DELETE 触发器来删除客户订单,并且在订单上有一个 BEFORE DELETE 触发器来删除订单项。如果客户没有订单,并且订单表触发器是行级触发器,那么它不会触发从订单项目中删除。
“在尝试删除之前检查是否存在相关行”可能没有好处。事实上,使用 SELECT 后跟 DELETE 会做更多的工作。
当然,休眠逻辑被打破了。删除会话只会看到(并尝试删除)已提交的事务。如果 FRED 已为客户插入订单,但未提交,则 JOHN 的删除(通过触发器)将看不到它或尝试删除它。但是,它仍然会“成功”并尝试删除父客户。如果您实际上在数据库中启用了外键约束,Oracle 将启动。它会等到 FRED 提交,然后拒绝删除,因为它有一个子项。如果外键约束不存在,则您有一个不存在的客户的订单。这就是为什么您应该在数据库中强制执行这种业务逻辑。
如果可能,请适当地修改和设置您的数据库表。- 如果您有一位 DBA 可供您使用,请让一位 DBA 参与进来。
您需要使用外键约束和级联删除。这消除了对触发器等的需要......
您可以查询特殊的 dba_objects 表:</p>
DECLARE
X NUMBER;
BEGIN
SELECT COUNT(*) INTO X FROM DBA_OBJECTS WHERE OBJECT_TYPE = 'TRIGGER' AND OBJECT_NAME = 'YOUR_TRIGGER_NAME_HERE';
IF X = 0 THEN
--Trigger doesn't exist, OK to delete...
END IF;
END;
select * from Tab where Tname = "TABLENAME"
如果此查询返回任何行,则该表存在,否则不存在。