数据库:原子触发器

时间:2014-04-24 20:58:23

标签: database oracle postgresql triggers relational-database

我有:假设我有一个表Info,其中列personIdlaptopIdprice

Taks:如果个人笔记本电脑的价格摘要超过某个常数,请阻止插入Person表。

解决方案不好:添加触发器

问题:该解决方案不是原子的。我的意思是在triger之间检查条件,我们继续INSERT,可能会执行另一个操作。

问题: 如何让它以安全的方式传播?

1 个答案:

答案 0 :(得分:2)

假设您在Info上创建了物化视图日志,您可以创建一个在提交时快速刷新的物化视图

CREATE MATERIALIZED VIEW mv_check_totals
  REFRESH FAST 
  ON COMMIT
AS
SELECT personID,
       sum( price ) total_price
  FROM info
 GROUP BY personID
HAVING sum( price ) > <<some constant>>

然后,您可以在此物化视图上创建一个约束,如果物化视图中出现任何行,则该约束将被违反

ALTER TABLE mv_check_totals
  ADD CONSTRAINT constraint_name
       CHECK( personID IS NULL )

有了这个,总价格将在提交时检查。您将被允许INSERT尽可能多的行(毕竟,其他人可能会删除您之前将提交的单独会话中的现有行)。但如果违反业务规则,您将被阻止提交更改。这非常类似于延迟约束所带来的行为。但它确实需要一个更智能的应用程序来识别提交失败并提醒用户注意这一事实,而不仅仅是报告特定INSERT的错误。

在此实现中,我将常量放在物化视图定义中,以便在满足业务规则时实例化视图为空。这避免了存储总额的成本。但是,您可能希望省略HAVING子句并将常量放在约束中。这意味着您要存储额外的数据。但这样可以更容易地在未来改变常量。如果您将要在报告中展示,那么它会为每个人实现total_price