在 SQL Server 中没有“从数据层”引发事件的“出色”机制。
一共有三个“OK”:
- 触发器(只能说可以)
触发器似乎是一个显而易见的解决方案,但你必须问自己......触发器实际上会做什么?如果它只是将数据写入另一个表,您仍然没有将自己置于数据库之外。您可以尝试使用各种神秘技巧,例如 CLR 过程或一些扩展过程。
但是如果你沿着这条路走,你必须开始考虑另一个考虑因素:触发器与导致它们触发的 DML 操作发生在同一个事务中。如果它们需要时间来执行,您将减慢 OLTP 工作负载。如果他们做了任何可能不可靠的事情,他们可能会失败,从而导致您的事务回滚。
- 触发器加服务代理
Service Broker 提供了一种机制——也许是唯一一种半明智的机制——以基于“推送”的方式将您的数据从 SQL 中取出并进入某种侦听器。您仍然有一个触发器,但触发器将数据写入服务代理队列。侦听器可以使用特殊的waitfor receive 语句来侦听出现在队列中的数据。这样做的好处是,一旦触发器将数据推送到代理队列,它的工作就完成了。该数据的“收据”与最初导致其排队的事务分离。这种服务代理机制就是 dot net 中内置的 SqlDependency 之类的东西所使用的。
服务代理的两个主要问题是复杂性和性能。服务代理的学习曲线陡峭,很容易出错。如果您需要扩展,性能会变得复杂,因为虽然构建 xml 或 json 有效负载“很容易”,但基于大型集合的数据更改可能意味着这些有效负载非常庞大。
无论如何,如果你想探索这条路线,你会想要阅读Remus Rusanu关于该主题的(所有)优秀文章
请记住,这是一种异步“近实时”机制,而不是触发器等同步“实时”机制。
- 轮询内置变更检测机制:CDC 或变更跟踪。
Sql server 带有两种技术,可以原生地“观察”表中发生的变化并记录它们:Change Tracking 和 Change Data Capture
这些都不是将数据推送到数据库之外,它们都是基于“拉取”的。他们所做的是在发生更改时将其他数据存储在数据库中。 CDC 可以提供每个更改的完整日志,而更改跟踪“指向”通过主键值更改的行。虽然这两个都涉及“投票历史”,但它们之间存在显着差异,因此请阅读细则。
请注意,CDC 是“双重异步”的——数据是从事务日志中读取的,因此记录数据不是原始事务的一部分。然后你必须轮询 CDC 数据,它不会推送给你。此外,当您启用 CDC 时,Microsoft 生成的功能可能会非常慢,只要您要求一些有用的东西,例如 net changes with mask(它可以告诉您哪些列真正改变了它们的值),并且您启用 CDC 的能力来了有很多警告和限制(同样,请阅读所有这些的文档)。
至于哪一个是“最好的”,那是见仁见智的问题。作为从 SQL 中获取事件的一种方式,我广泛使用了 CDC,很少使用服务代理,并且几乎从不使用触发器。我从未在生产环境中实际使用过变更跟踪,但如果我再次有选择,我可能会选择变更跟踪而不是变更数据捕获,至少直到或除非有要求强制使用 CDC,因为它的附加功能超出变更跟踪所能提供的功能。
最后一点:如果您需要“保证”引发的事件实际上已被侦听器收集并成功转发给订阅者,那么您还有一些工作要做!有保证的消息传递很难。