过去,我从来不喜欢在数据库表上使用触发器。对我来说,它们总是代表着数据库端将发生的一些“魔法”,远离我的应用程序代码的控制。我还想限制数据库必须完成的工作量,因为它通常是共享资源,并且我始终认为触发器在高负载情况下可能会变得昂贵。

也就是说,我发现了几个使用触发器有意义的实例(至少在我看来它们是有意义的)。但最近,我发现自己有时可能需要“绕过”触发器。我对必须寻找方法来做到这一点感到非常内疚,并且我仍然认为更好的数据库设计将减轻这种绕过的需要。不幸的是,这个数据库被多个应用程序使用,其中一些应用程序是由一个非常不合作的开发团队维护的,他们会对架构更改大喊大叫,所以我陷入了困境。

关于触发器的普遍共识是什么?爱他们吗?讨厌他们?认为它们在某些情况下有用吗?您是否认为需要绕过触发器就意味着您“做错了”?

有帮助吗?

解决方案

触发器通常使用不当,会引入错误,因此应该避免。切勿设计触发器来执行跨表中行的完整性约束检查(例如“部门的平均工资不能超过 X”)。

汤姆·凯特, ,甲骨文副总裁表示他更愿意 删除触发器作为 Oracle 的一项功能 数据库由于其频繁出现的错误。他知道这只是一个梦想,触发器将继续存在,但如果可以的话,他会从 Oracle 中删除触发器(连同 WHEN OTHERS 子句和自主事务)。

触发器能正确使用吗?绝对地。

问题是 - 在许多情况下,它们无法正确使用,以至于我愿意放弃任何感知的福利,只是为了摆脱由它们造成的虐待(和错误)。- 汤姆·凯特

其他提示

将数据库视为一个巨大的对象 - 每次调用它之后,它都应该处于逻辑一致的状态。

数据库通过表公开自身,并且可以通过触发器来保持表和行的一致性。保持它们一致的另一种方法是禁止直接访问表,而只允许通过存储过程和视图进行访问。

触发器的缺点是任何操作都可以调用它们;这也是一种优势——没有人会因为无能而破坏系统的完整性。

相反,仅允许通过存储过程和视图访问数据库仍然允许后门访问权限。拥有足够权限的用户被信任不会破坏数据库完整性,所有其他用户都使用存储过程。

关于减少工作量:当数据库不需要与外界打交道时,它们的效率惊人;您会非常惊讶即使是进程切换也会对性能造成如此大的影响。这是存储过程的另一个优点:而不是对数据库的十几次调用(以及所有相关的往返),只有一次。

将内容打包在一个存储过程中很好,但是当出现问题时会发生什么?假设您有 5 个步骤,第一个步骤失败了,其他步骤会怎样?您需要在其中添加一大堆逻辑来满足这种情况。一旦开始这样做,您就会失去该场景中存储过程的优势。

业务逻辑必须到某个地方,并且数据库的设计中嵌入了许多隐含的域规则 - 关系、约束等是试图将业务规则编纂为代码,例如,一个用户只能有一个密码。假设您已经开始通过这些关系等将业务规则推送到数据库服务器上,那么您在哪里划清界限?数据库何时放弃对数据完整性的责任,并开始信任调用应用程序和数据库用户以确保数据正确?嵌入这些规则的存储过程可以将大量的政治权力交到 DBA 手中。这取决于您的 n 层架构中将存在多少层;如果有表示层、业务层和数据层,那么业务和数据的分离点在哪里?业务层增加了哪些附加值?您会将业务层作为存储过程在数据库服务器上运行吗?

是的,我认为必须绕过触发器意味着你“做错了”;在这种情况下,触发器不适合您。

enter image description here

我使用 c# 中的网络和 winforms 应用程序,并且我 激发激情。我从未遇到过这样的情况:我可以证明使用触发器而不是将该逻辑移动到应用程序的业务层并在那里复制触发器逻辑。

我不做任何 DTS 类型的工作或类似的事情,所以可能有一些使用触发器的用例,但如果我的任何团队中的任何人说他们可能想要使用触发器,他们最好准备好他们的论点因为我拒绝袖手旁观,让触发器添加到我正在处理的任何数据库中。

我不喜欢触发器的一些原因:

  • 他们将逻辑移入数据库。一旦你开始这样做,你就会陷入痛苦的境地,因为你失去了调试、编译时安全性和逻辑流程。一切都是下坡路。
  • 他们实现的逻辑并不容易被任何人看到。
  • 并非所有数据库引擎都支持触发器,因此您的解决方案会创建对数据库引擎的依赖关系

我确信我可以立即想到更多的原因,但仅凭这些就足以让我不使用触发器。

“永远不要设计触发器来执行跨表中行的完整性约束检查”——我不同意。问题被标记为“SQL Server”,并且 SQL Server 中的 CHECK 约束子句不能包含子查询;更糟糕的是,该实现似乎有一个“硬编码”假设,即 CHECK 仅涉及单行,因此使用函数并不可靠。因此,如果我需要一个合法地涉及多行的约束——这里的一个很好的例子是经典“有效时间”时态表中的排序主键,我需要防止同一实体的重叠周期——如何才能我在没有触发器的情况下这样做?请记住,这是一个主键,可以确保数据完整性,因此不可能在 DBMS 之外的任何地方强制执行它。在 CHECK 约束获得子查询之前,我没有看到对某些类型的完整性约束使用触发器的替代方法。

触发器非常有帮助。它们也可能非常危险。我认为它们非常适合内部清理任务,例如填充审核数据(创建者、修改日期等),并且在某些数据库中可用于引用完整性。

但我不太喜欢将大量业务逻辑放入其中。这可能会给支持带来问题,因为:

  • 这是需要研究的额外代码层
  • 有时,正如 OP 了解到的那样,当您需要进行数据修复时,触发器可能会假设数据更改始终通过应用程序指令进行,而不是来自修复问题的开发人员或 DBA,甚至来自不同的人员。应用程序

至于必须绕过触发器来做某事,这可能意味着你做错了什么,或者可能意味着触发器做错了什么。

我喜欢使用触发器的一般规则是保持它们轻便、快速、简单且尽可能非侵入性。

我发现自己在进行批量数据导入时绕过了触发器。我认为在这种情况下这是合理的。

如果您最终经常绕过触发器,您可能需要再次考虑一下您最初将它们放在那里的目的。

一般来说,我会投票支持“它们在某些情况下有一定的用途”。我总是对性能影响感到紧张。

就我个人而言,我不是粉丝。我将使用它们,但仅当我发现代码中的瓶颈(可以通过将操作移至触发器中来清除)时才使用它们。一般来说,我更喜欢简单性,让事情变得简单的一种方法是将逻辑保留在一个地方 - 应用程序。我也曾从事过访问权限非常分散的工作。在这些环境中,我打包到触发器中的代码越多,即使是最简单的修复,我也必须聘请更多的人。

几周前我第一次使用触发器。我们将生产服务器从 SQL 2000 更改为 SQL 2005,我们发现驱动程序对 NText 字段(存储大型 XML 文档)的行为有所不同,会丢失最后一个字节。我使用触发器作为临时修复,在数据末尾添加一个额外的虚拟字节(空格),解决我们的问题,直到推出适当的解决方案。

除了这种特殊的临时情况之外,我想说我会避免它们,因为它们确实隐藏了正在发生的事情,并且它们提供的功能应该由开发人员明确处理,而不是作为一些隐藏的魔法。

老实说,我唯一一次使用触发器来模拟唯一索引,该索引允许具有不计入唯一性的 NULL。

关于减少工作量:当数据库不需要与外界打交道时,它们的效率惊人;您会非常惊讶即使是进程切换也会对性能造成如此大的影响。这是存储过程的另一个优点:而不是对数据库的十几次调用(以及所有相关的往返),只有一次。

这有点偏离主题,但您还应该意识到,您只是从一个潜在的积极方面来看待这个问题。

将内容打包在一个存储过程中很好,但是当出现问题时会发生什么?假设您有 5 个步骤,第一个步骤失败了,其他步骤会怎样?您需要在其中添加一大堆逻辑来满足这种情况。一旦开始这样做,您就会失去该场景中存储过程的优势。

粉丝总数,

但确实必须谨慎使用它,

  • 需要保持一致性(特别是当维度表用于仓库时,我们需要将事实表中的数据与其适当的维度相关联。有时,维度表中正确的行的计算成本可能非常昂贵,因此您希望将键直接写入事实表,维护“关系”的一种好方法是使用触发器。

  • 需要记录更改(例如在审核表中,了解 @@user 进行了哪些更改以及何时发生更改很有用)

一些 RDBMS(如 sql server 2005)还为您提供 CREATE/ALTER/DROP 语句的触发器(这样您就可以知道谁创建了哪个表、何时、删除了哪些列等)

老实说,在这三种情况下使用触发器,我不明白为什么您需要“禁用”它们。

一般经验法则是:不要使用触发器。如前所述,它们增加了开销和复杂性,通过将逻辑移出数据库层可以轻松避免这些开销和复杂性。

此外,在 MS SQL Server 中,每个 sql 命令都会触发一次触发器,而不是每行触发一次。例如,下面的sql语句只会执行一次触发器。

UPDATE tblUsers
SET Age = 11
WHERE State = 'NY'

许多人,包括我自己,都认为触发器会在每一行上触发,但事实并非如此。如果您有像上面这样的 sql 语句,可能会更改多行中的数据,那么您可能需要包含一个游标来更新受触发器影响的所有记录。您可以看到这如何很快变得复杂。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top