200

数据库触发器是个坏主意吗?

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

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

我们唯一一次使用触发器是为了非常简单的事情,比如设置ModifiedDate.

4

20 回答 20

166

触发器的主要问题是

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

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

于 2009-01-20T07:22:43.203 回答
86

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

我们大量使用触发器,因为它将特定于 DBMS 的活动置于其所属数据库的控制之下。DBMS 的用户不必担心这类事情。数据的完整性取决于数据库本身,而不是使用它的应用程序或用户。如果数据库中没有约束和触发器以及其他功能,则留给应用程序执行规则,并且只需要一个流氓或错误的应用程序/用户来破坏数据。

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

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

于 2009-01-20T07:16:04.857 回答
55

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

于 2009-01-20T19:19:01.823 回答
22

我同意。触发器的问题在于人,而不是触发器。尽管它需要更多地查看、更多地考虑并增加编码人员正确检查事物的责任,但我们不会丢弃索引以使我们的生活更简单。(坏索引可能和坏触发器一样坏)

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

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

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

他们听起来很刺耳,我猜他们是。但这是基本事实,在我看来...

于 2009-01-20T09:46:43.570 回答
20

我认为触发器不仅不是邪恶的,而且是良好的数据库设计所必需的。应用程序程序员认为数据库只受其应用程序的影响。他们经常是错的。如果要保持数据完整性,无论数据来自何处,触发器都是必需的,避免它们是愚蠢的,因为一些程序员过于以民族为中心,认为除了他们珍贵的应用程序之外的其他东西可能会影响事物。如果您是一位称职的数据库开发人员,那么设计、测试或排除触发器故障并不难。也很难确定触发器是否会导致意外结果,如果它发生在您身上(就像它发生在我身上一样)看那里。如果我收到一条错误消息,指出我没有在我的 sp 中引用的表有 FK 错误,我想都没想就知道是触发器导致了问题,任何称职的数据库开发人员也应该如此。仅将业务规则放在应用程序中是我发现不良数据的首要原因,因为其他人甚至不知道规则存在并在他们的流程中违反它。以数据为中心的规则属于数据库,触发器是执行更复杂规则的关键。

于 2010-02-03T20:27:11.967 回答
13

大多数情况下,是的。

触发器的困难在于它会“在你背后”做一些事情。维护应用程序的开发人员很容易没有意识到它的存在,并且在没有注意到的情况下进行了更改,从而搞砸了事情。

它创造了一层复杂性,只会增加维护工作。

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

于 2009-01-20T10:15:16.617 回答
9

触发器非常强大和有用,在许多情况下触发器是问题的最佳解决方案。

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

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

于 2009-01-20T10:35:49.477 回答
8

触发器有它们的用途 - 记录/审计和维护“最后修改”日期是两个非常好的用途,在之前的回复中已经提到过。

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

还有已经提到的“最小意外原则”问题。

于 2009-01-20T11:32:32.810 回答
7

概括地说,触发器有两个用例1

1)让事情“自动”发生。在这种情况下,触发器会产生副作用,它们会以不期望的方式更改数据,因为(原始)运算符插入、更新或删除已执行并导致触发器触发。

这里的普遍共识是触发器确实是有害的。因为它们改变了众所周知的 INSERT、UPDATE 或 DELETE 语句的语义。更改这三个原始 SQL 操作符的语义会影响其他开发人员,他们以后需要处理您的数据库表,当使用 SQL 原语对它们进行操作时,这些表不再以预期的方式运行。

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

为后一个用例使用触发器是无害的。

我在写博客:http: //harmfultriggers.blogspot.com

于 2011-11-30T13:59:25.453 回答
6

如果使用得当,触发器是一个很好的工具。特别是对于审计更改、填充汇总表等。

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

所以,是的,如果你能正确看待你正在做的事情,它们会很棒。如果它是非常简单的事情,比如审计、总结、自动排序等,那就没有问题了。请记住表的增长率以及触发器将如何影响性能。

于 2009-03-03T15:55:51.757 回答
5

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

但是,我个人完全同意 MarkR - 您可以(几乎)始终编写功能上等同于触发器的代码,这将更加明显,因此更易于维护。

于 2009-01-20T10:22:51.297 回答
5

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

1.记录/审计记录甚至数据库模式的更改

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


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

于 2009-01-20T10:28:15.140 回答
4

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

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

于 2009-01-20T10:57:44.207 回答
4

他们绝对不是邪恶的。我发现在重构数据库模式、重命名列或将列拆分为两列或反之亦然(例如:姓名/姓氏大小写)并协助转换时,触发器很重要。

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

于 2010-04-29T06:51:26.360 回答
4

这个答案特别适用于 SQL Server。(虽然它也可能适用于我不知道的其他 RDBMS。我宁愿在这里给出它作为答案,但由于这个问题而被关闭。)

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

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

于 2011-04-24T12:36:17.327 回答
3

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

于 2009-01-20T07:03:51.323 回答
3

我认为它们可能是邪恶的,但只能与开发中的其他任何东西一样邪恶。

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

我认为它与使用存储过程类似。您通常会有非常擅长将业务逻辑写入数据库的 SQL 的开发人员,而不擅长的开发人员则将他们的业务逻辑放在其他地方。

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

于 2009-01-20T10:40:21.090 回答
3

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

触发器有一个有效的用途,但往往作为一种复古黑客,最终使事情变得更糟。

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

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

于 2009-01-20T10:44:24.653 回答
1

事实上,触发器经常被滥用。实际上,在大多数情况下,您甚至不需要它们。但这并不意味着它们一定是坏的。

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

于 2009-01-20T07:23:41.640 回答
1

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

于 2010-02-16T18:59:36.907 回答