数据库触发了邪恶吗?[关闭]


186

数据库触发一个坏主意吗?

以我的经验,它们是邪恶的,因为它们可能导致令人惊讶的副作用,并且难以调试(尤其是当一个触发器触发另一个触发器时)。通常,开发人员甚至根本不考虑是否存在触发器。

另一方面,如果您有每次FOO在数据库中创建新逻辑时都必须发生的逻辑,则放置它的最简单方法是在FOO表上插入触发器。

我们唯一使用触发器的时间是用于设置设置等非常简单的事情ModifiedDate


30
这是一个完全合法的问题,但我不太喜欢耸人听闻的标题。我认为诸如“实现数据库触发器时要考虑的最重要的问题是什么?”之类的东西。会好得多。
2009年

2
该问题已关闭,无法添加答案,但另请参见数据库触发器对于跨表完整性约束是否安全?。(剧透:不,不是)
Mifeet

16
这个网站让我非常生气。这是一个伟大的问题,但与其他许多问题一样,它是封闭的,因为人们缺乏想象力,无法接受由于某些外来原因而不得不遵循的问答形式的原始二进制格式。
Quibblesome

1
触发器中的业务逻辑是有问题的(如果有的话,这是邪恶的)。触发器中的数据库逻辑没有问题(完整性,日志记录)。
格雷格·古姆

1
我喜欢依靠IDE进行代码导航并了解正在发生的事情。如果一半的逻辑是在数据库中,而另一半是选择的编程语言,则我不能这样做。与触发器相比,我发现创建每个请求都必须经过的控制器更加容易。所有“触发器”都可以在那里应用。
穆罕默德·乌默尔

Answers:


147

触发器的主要问题是

  • 它们完全是全局的-无论表活动的上下文如何,它们都适用;
  • 他们是隐形的;容易忘记它们在那里,直到它们以意想不到的(非常神秘的)后果伤害了您。

这只是意味着需要在适当的情况下谨慎使用它们。根据我的经验,这仅限于关系完整性问题(有时粒度要比声明性要好);通常不用于商业或交易目的。YMMV。


20
在某些情况下,这是2个优点。
2009年

18
是的,“ Stealthy”是个好词,说得好。这就是我倾向于回避它们的原因:它们常常被遗忘或忽略。以我的亲身经历,重新审视触发器常常伴随着对自己额头的a打。
Christian Nunciato

5
全球性就是为什么它们对于数据完整性和审核之类的东西都是好和必要的。这不是减号,而是加号。
HLGEM 2010年

4
所以@RobertŠevčík-Robajz,您是说所有认识的开发人员都不称职?
HLGEM 2012年

3
@HGLEM,同意应该由专家来制定触发器。现实生活中的情况-没有。现实生活中的场景-花费几天时间来识别与被遗忘的触发器相关的错误。现实生活中的情况-触发逻辑正急切地推入应用程序逻辑中,可以轻松地对其进行重构和单元测试。我所面对的现实生活使我说“远离扳机”……这不是扳机的错,因为窗户破裂不是石头的错。
Rbjz

80

不,实际上这是个好主意。如果您的特定触发器存在问题,那么您就没有正确地执行它们,但这通常意味着您的实现存在问题,而不是触发器本身的概念:-)。

我们使用触发器的原因很多,因为它将特定于DBMS的活动置于其所属数据库的控制之下。DBMS的用户不必担心这种事情。数据的完整性在于数据库本身,而不是数据库的应用程序或用户。在数据库中没有约束,触发器和其他功能的情况下,它留给了应用程序来执行规则,并且只需要一名流氓或越野车应用程序/用户即可破坏数据。

例如,没有触发器,就不会存在诸如自动生成的列之类的奇妙事物,并且在选择它们时必须在每一行上处理一个函数。这很可能会破坏DBMS的性能,在插入/更新时创建自动生成的列会更好,因为这是唯一的更改时间。

同样,缺少触发器将阻止在DBMS强制执行数据规则,例如预触发以确保列具有特定格式。请注意,这不同于数据完整性规则,后者通常只是外键查找。


9
“选择它们时在每一行上处理一个函数”。为此目的,最好使用基于函数的索引而不是触发器。
tuinstoel

10
不一定,触发器仅可能在插入或更新该行时运行。基于功能的索引将针对每个选择运行。根据使用模式,一种可能比另一种更好。但是,两者总是比对方更好。
jmucchiello 2010年

@tuinstoel:我有你的声明同意一些时间。例如,Oracle仅在可以证明功能是确定性的情况下才创建基于功能的索引。有时这只是无法证明的(例如,如果函数涉及从表中查找,即使您知道表的数据永不更改)。
亚当·佩恩特

50

工具从不邪恶。这些工具的应用可能是邪恶的。


11
阅读评论后,我再也没有受到更多的抵触了。一方面,我赞成第二修正案,并认为枪支并不是天生的邪恶:而是使用枪支的人。另一方面,我认为触发因素是邪恶的……我想我正在生存崩溃……
vbullinger 2012年

37
@vbullinger的枪不是邪恶的,但是它们的触发器是;)
Darragh Enright 2014年

2
:D概括很危险(递归)。您有没有被审讯官用来“触发”认罪的酷刑“工具”?+1仍然是透视图。
Rbjz 2015年

22

我同意。触发器的问题是人,而不是触发器。尽管需要更多的关注,需要更多的考虑,并增加了编码人员正确检查事情的责任,但我们不会丢弃索引来简化我们的生活。(不良索引可能与不良触发器一样糟糕)

触发器的重要性(在我看来)是...-
任何系统都应始终处于有效状态
-强制执行此有效状态的代码应集中化(并非在每个SP中都编写)

从维护的角度来看,触发器对于有竞争力的编码员和初级或业余爱好者而言非常有用。但是,这些人需要学习和以某种方式成长。

我想这取决于您的工作环境。您是否有可靠的人,他们学得很好并且可以被信奉为有条理的人?如果不是,您似乎有两个选择:
-接受必须失去功能才能弥补的
-接受您需要不同的人员或更好的培训和管理

它们听起来很刺耳,我想是的。但这是我的基本真理...


3
>>>触发器的问题是人。是的,如果只有人可以在汇编中进行编码,使用糟糕的GUI并正确猜测是推还是拉设计不良的门……任何反复出现错误的“特征”人就是“邪恶”。
Fakrudeen

1
@Fakrudeen,任何触发触发器错误的开发人员都无法访问数据库。
HLGEM 2014年

20

我认为触发器不仅有害,而且对于良好的数据库设计是必要的。应用程序程序员认为数据库仅受其应用程序影响。他们通常是错误的。如果无论数据变化来自何处都要保持数据完整性,就必须要有触发器,并且避免使用触发器是愚蠢的,因为某些程序员出于种族中心思想,以至于认为除珍贵的应用程序以外的其他事物可能会影响事物。如果您是一位有能力的数据库开发人员,则不难设计,测试或对触发器进行故障排除。如果您(像我一样)看到触发器,也很难确定触发器是否导致意外结果。如果我收到一条错误消息,说我未在sp中引用的表存在FK错误,我什至不考虑触发器是导致问题的原因,因此任何有能力的数据库开发人员也应如此。仅在应用程序中放置业务规则是我发现不良数据的第一原因,因为其他人不知道规则甚至存在并在其流程中违反它。以数据为中心的规则属于数据库,触发器是执行更复杂规则的关键。


以数据为中心的规则属于数据库中
6

有我some programmers are too ethnocentric to consider that something other than their prized application may be affecting things
Kid101

13

通常,是的。

触发器的困难在于它确实会“藏在背后”。维护该应用程序的开发人员很容易无法意识到它的存在,并进行更改以至于无所适从。

它创建了一层复杂性,仅增加了维护工作。

通常可以使存储过程/例程执行相同的操作,而不是使用触发器,但是可以以一种清晰且可维护的方式进行操作-调用存储例程意味着开发人员可以查看其源代码并确切了解正在发生的事情。


12
这是触发器的优点,而不是缺点!不能保证每次更改数据都会调用存储的proc。除了GUI之外,还有许多方法可以更改数据。
HLGEM,2009年

2
HLGEM,这取决于您的访问控制。您可以直接拒绝对表的任何修改,除非通过存储过程。
拉比斯

1
我认为关键是,例如,无论您如何访问数据库,无论您是谁或拥有什么权限,都应该一起创建和销毁两个表中的记录,那么触发器是唯一合法的解决方案。甚至有可能分配太多或不正确的权限并期望人们知道要使用哪些存储过程这一事实,就意味着数据库有失去完整性的风险。它与外键关系完全相同。它只是数据库引擎强制执行的“最佳且最可靠”。
Triynko

2
如果应该始终一起创建/销毁记录,请创建一个检查约束以确保它们是正确的。这样,违反规则的人将得到错误,而不是隐藏的行为,这种行为在没有他们的知识或同意的情况下魔术地使事情正确。
MarkR 2013年

9

触发器功能极其强大且非常有用,在许多情况下,触发器都是解决问题的最佳方法。

它们也是一个很好的“ hack”工具。在很多情况下,您无法同时控制代码和数据库。如果您需要等待2个月才能发布代码的下一个主要版本,但是可以立即将补丁应用到数据库,则可以在表上放置触发器以执行一些其他功能。然后,在有可能发布代码时,如果需要,您可以使用相同功能的编码版本替换此触发器。

归根结底,如果您不知道它在做什么,那么一切都是“邪恶的”。确定触发器是因为有些开发人员对它们不了解,这与认为汽车是邪恶的,因为有人无法驾驶...


7

触发器有其用途-记录/审核和维护“最后修改”日期是在先前的答复中提到的两个很好的用途。

但是,良好设计的核心原则之一是业务规则/业务逻辑/无论您想称呼什么,都应该集中在一个地方。将某些逻辑(通过触发器或存储的proc)放入数据库中,而将某些逻辑放入应用程序中,则违反了该原理。在两个地方重复逻辑甚至更糟,因为它们总是会彼此不同步。

已经提到了“最不惊奇的原理”问题。


3
没错,它应该放在一个数据库中。影响数据完整性的逻辑必须始终存在于数据库中,而永远不要存在于影响数据库中的数据时可能会或可能不会被调用的应用程序中。
HLGEM 2010年

1
@HLGEM:这取决于数据库是否可以访问允许其判断数据是否有效的信息。并非总是如此。当验证者在另一个组织中时(例如,用于信用卡或银行帐户的详细信息),那么数据库就无法知道它是否正确-假设这不是银行的数据库!—它必须依靠该应用程序来执行。您不希望数据库随机连接到第三方服务,因为这对服务器部署来说是不好的。
Donal Fellows 2010年

@HLGEM:尽管我还没有准备好完全排除将所有应用程序逻辑放入数据库中的选项,但我发现将其放置在其他地方通常会更好,通常是可重用的OO层,可用于所有应用程序访问数据库。只要您的应用仅通过对象层访问数据库,始终被调用的逻辑的相同保证仍然适用。
戴夫·谢罗曼

2
从未在仅通过Object层将数据插入数据库的业务应用程序上工作,而我不想在其中工作。通过旨在仅处理一个记录时间的流程来放置数百万个记录的进口或所有价格的更新是愚蠢的。对象层恰恰是实施数据完整性的错误位置,这就是为什么这么多数据库存在完整性问题的原因。
HLGEM 2010年

正是由于这个原因,我正在对ORM进行扩展,使其可以像使用事务中所有内容的变更集的触发器一样工作。感觉有点愚蠢,但是会阻止我们在应用程序中拥有所有业务逻辑,除非不是几次(只有少数几个表需要批量更新)。它还将允许所有开发人员以他们最熟悉的语言来编写和使用它们,并且可以在其中访问我们已构建的所有对象抽象。
精金

6

正确使用触发器是不错的工具。特别适用于审核变更,填充汇总表等。

现在,如果您以一个触发其他触发的触发而陷入“触发地狱”,那么它们可能是“邪恶的”。我曾经在COTS产品上工作过,在那里他们有了所谓的“柔性触发器”。这些触发器存储在表中,因为每次执行时都会编译动态sql字符串。编译的触发器将进行查找,并查看该表是否有任何要运行的flex触发器,然后编译并运行“ flex”触发器。从理论上讲,这听起来像是一个很酷的主意,因为该产品易于定制,但实际上,由于必须进行所有编译,因此数据库几乎爆炸了。

是的,如果您以正确的眼光看待他们,那很棒。如果这很简单,例如审核,汇总,自动排序等,则没有问题。只需记住表的增长率以及触发器将如何影响性能。


6

概括而言,触发器有两个用例1

1)使事物“自动”发生。在这种情况下,触发器会产生副作用,它们会以给定的(原始)操作员插入,更新或删除操作(执行触发器并触发)的方式来改变数据。

这里的普遍共识是触发器确实是有害的。因为它们更改了INSERT,UPDATE或DELETE语句的众所周知的语义。更改这三个基元SQL运算符的语义将使其他开发人员感到痛苦,这些开发人员将来需要在使用SQL基元对它们进行操作时不再以预期的方式处理数据库表。

2)为了执行数据完整性规则,除了可以声明式处理的规则外(使用CHECK,PRIMARY KEY,UNIQUE KEY和FOREIGN KEY)。在此用例中,所有触发器都使用QUERY(SELECT)数据来验证是否允许由INSERT / UPDATE / DELETE进行的更改。就像声明性约束对我们所做的一样。仅在这种情况下,我们(开发人员)才对执法进行了编程。

在后一种用例中使用触发器不会造成危害。

我在以下网址发布博客:http//harmfultriggers.blogspot.com


当使用触发器实现参照完整性时,它比处理并发问题要困难。
WW。

2
同意 但是使用其他方法会更容易吗?
Toon Koppelaars,2011年

我认为,只有开发人员不称职的人才是第一害。
HLGEM 2015年

尽管有很多不称职的开发人员。
hashtable

5

我知道开发人员认为触发器应该始终用于实现他们想要的功能的最直接方法,而永远不会使用。这就像两个阵营之间的教条。

但是,我个人完全同意MarkR-您(几乎)总是可以在功能上等效于触发器,从而使代码更加清晰,因此更易于维护。


并非所有命中数据库的工作都流经应用程序代码。
HLGEM

5

不邪恶。他们实际上简化了诸如

1,记录/审核记录甚至数据库模式的更改

您可以在ALTER TABLE上有一个触发器,以回滚生产环境中的更改。这样可以防止意外修改表。


2.在多个数据库中强制执行引用完整性(主/外键关系等)


您可以回滚DDL语句吗?
安德鲁·斯旺

通常不会。停止此操作的唯一方法是从用户登录名中删除该权限。
jmucchiello 2010年

在某些数据库引擎中,您可以(例如PostgreSQL)。
尼古拉斯

@Andrew-在SQL Server中可以。SQL Server 2005+还具有在诸如之类的事件上触发的DDL触发器ALTER TABLE
马丁·史密斯

4

不,他们不是邪恶的-他们只是被误解了:-D

触发器具有有效的用法,但经常作为一种回溯攻击,最终会使情况变得更糟。

如果将数据库作为应用程序的一部分进行开发,则逻辑应始终在进行调用的代码或存储过程中。触发器将稍后导致调试痛苦。

如果您了解锁定,死锁以及数据库如何访问磁盘上的文件,那么以正确的方式使用触发器(例如审核或归档直接数据库访问)将非常有价值。


4

说它们是邪恶的是夸大其词,但它们可能导致网状化。当一个触发器的触发导致其他触发器触发时,它变得非常复杂。假设它们很麻烦:http : //www.oracle.com/technology/oramag/oracle/08-sep/o58asktom.html

由于多并发问题,使用触发器在Oracle中进行业务逻辑比看起来要困难。在其他会话提交之前,您不会在其他会话中看到更改。


4

他们绝对不是邪恶的。我发现在数据库模式重构,重命名一列或将一列拆分为两列(反之亦然,例如名称/姓氏)并协助过渡的过程中,触发器很珍贵。

它们对于审核也非常有用。


4

此答案专门适用于SQL Server。(尽管它也可能适用于我不知道的其他RDBMS。我希望在这里给出答案作为答案但这是对它的欺骗。)

到目前为止,任何答案中都没有提到的一个方面是安全性。因为默认情况下,触发器是在执行导致触发器触发的语句的用户的上下文中执行的,除非所有触发器都经过检查,否则这可能会导致安全威胁。

BOL中“ 管理触发器安全性 ”标题下给出的示例是用户创建一个包含代码的触发器GRANT CONTROL SERVER TO JohnDoe ;以提升自己的权限的用户。


3

如果有副作用,这是设计上的问题。在某些数据库系统中,没有其他可能性来设置自动递增字段,即为主键ID字段。


3

我认为它们可以是邪恶的,但只能与发展中的其他事物一样邪恶。

尽管我实际上对他们并没有太多的经验,但是我确实在最近的一个项目中让他们参与其中,这使我得出了这个结论。我遇到的问题是它们可能导致业务逻辑最终出现在两个位置,即代码库数据库。

我将其视为使用sproc的类似参数。您经常会遇到真正擅长SQL的将开发人员将业务逻辑写入数据库的开发人员,而没有开发人员的开发人员将在其他地方拥有其业务逻辑。

因此,我的经验法则是查看项目的结构。如果将业务逻辑存储在数据库中似乎可行,那么使用触发器可能会很有用。


1

确实,触发器经常被滥用。实际上,在大多数情况下,您甚至不需要它们。但这并不一定会使它们变坏。

我想到的一个触发器有用的场景是,当您有一个遗留应用程序而您没有源代码并且无法更改它时。


1

触发器的想法不是邪恶的,限制触发器的嵌套是邪恶的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.