如果在 INSERT 或 UPDATE 期间发生更改,如何将数据转发到外部系统?使用触发器?使用扩展 Sproc 或 CLR 集成?

Posted

技术标签:

【中文标题】如果在 INSERT 或 UPDATE 期间发生更改,如何将数据转发到外部系统?使用触发器?使用扩展 Sproc 或 CLR 集成?【英文标题】:How To Forward Data To An External System If There Were Changes During An INSERT or UPDATE? Use a Trigger? Use Extended Sproc or CLR Integration? 【发布时间】:2009-07-23 16:59:45 【问题描述】:

以下是我们今天所采用的系统的基础知识。我们有一个 SQL 2005/2008 表定义为:

CREATE TABLE [dbo].[Profiles] (
    [Firm] [char] (4) NULL ,
    [Account] [char] (10) NOT NULL ,
    [UndSym] [char] (24) NOT NULL ,
    [Updated] [timestamp] NOT NULL ,
    [Data] [image] NOT NULL 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

数据字段是一个 BLOB。几乎所有的好东西都在这里。 BLOB 中的数据是压缩文本,看起来非常类似于 INI 文件,在部分内具有键值对。此 INI 文件的内部布局相当复杂,但包含许多相互关联的数据。

我们还有另一个在设计、实施和目标受众方面完全不同的产品系列。但是现在我们有一个客户上线了,他想在数据库级别集成这两个系统。

我的系统是 MSSQL。另一个系统是 mysql。两者之间是我们自己设计的定制中间件解决方案。我不想直接连接到 MySQL,他们也不想直接连接到我,出于各种合理且超出本次讨论范围的原因,所以不要担心。

这个概念很简单。当我的 Profiles 表中的一行被触摸时,我需要翻开 BLOB 并查找一些数据。如果这些数据位发生了变化,我只需将这些数据位(而不是整个 BLOB)发送到中间件。我必须只在有我感兴趣的更改时才这样做,而我能做到这一点的唯一方法是处理两个 blob(原始和替换)。

我很快得出结论,使用 T-SQL 处理 BLOB 不是我想走的路。我需要编写自定义代码,并且只能使用非托管 C++、托管 C++ 或 C# 来完成。

这里有几个问题。

FIRST:我应该使用 INSTEAD OF 触发器来触发比较 BLOB 并发送有趣数据的代码吗?我知道有一些关于触发器的极端思想流派:有些人认为他们是纯粹的邪恶,其他人认为他们很棒。真相介于两者之间。如果不使用触发器,如何触发处理 BLOB?

第二个:我应该使用:

    用非托管 C++ 编写的扩展存储过程? 用托管 C++ 或 C# 编写的 CLR 存储过程? 还有别的吗?

...对 BLOB 进行实际处理并将数据发送到中间件?

【问题讨论】:

顺便说一句:不要为 XP 烦恼。它们是过去时代的产物。 XP 能做的一切 CLR 都能做得更好。 【参考方案1】:

不要在触发器中连接到外部进程,否则会造成混乱。

在插入/更新时使用SEND 将消息排队到本地服务的表上添加一个触发器。将activated 过程附加到服务队列。在 INSERT/UPDATE 提交后,入队的消息将激活该过程,您可以使消息出队并连接到您的中间件逻辑(例如,通过 CLR)。这样您就可以将更新/插入事务与通知分离。这对性能(不再需要等待连接到中间件在触发期间完成)和正确性(INSERT/UPDATE 可以安全回滚而无需在分布式事务中注册中间件和/或 MySQL)都是有益的.

您可以在触发器或激活过程中使用“有趣的数据”检测逻辑。如果是 T-SQL,我会把它放在触发器中。如果你把它放在 CLR 过程中,我会把它放在激活部分。

为了使您激活的过程能够与外部连接,您很可能需要对连接到中间件的部分进行代码签名。请参阅此处example of how to sign an activated procedure。

【讨论】:

这种回应正是我在 SO 上发帖的原因。非常感谢。【参考方案2】:

同意 Remus,不要将触发器连接到外部进程。如果您可以等待几分钟来同步数据,请考虑通过触发器将所有感兴趣的 blob 发送到单独的表中。然后有一个每五分钟左右运行一次的作业,并拾取处理数据并发送到另一个系统,然后将这些记录标记为已处理。这还具有能够及时回顾并查看特定数据何时发送到其他系统的优势。请务必在此处考虑竞争条件,确保将所有要发送到临时表或表变量的数据拉出并从 htere 处理,这样您就不会在处理过程中将未发送但获取的记录添加到表中标记为已发送。

如果您可以保证数据永远不会在用户界面之外更改,您可以考虑将处理步骤添加到插入或更新过程的代码中,而不是使用触发器。但是,当试图使两个系统保持同步时,这是很危险的。

【讨论】:

有趣的建议。但是不确定它是否可以在我们的系统中运行——这是一个交易系统,5 分钟是永恒的。一个问题,寿。此解决方案的存储过程中是否存在与中间件的连接?这是否会使我的系统面临与将触发器附加到中间件相同的风险? 运行实际进程的 proc 会击中侧表,而不是主表,因此它不会像将其附加到主表上的触发器那样具有相同的风险。但是如果你需要立即行动,Remus 有一个更好的建议。

以上是关于如果在 INSERT 或 UPDATE 期间发生更改,如何将数据转发到外部系统?使用触发器?使用扩展 Sproc 或 CLR 集成?的主要内容,如果未能解决你的问题,请参考以下文章

Mysql----insert/update/delete

SQL 命名法:INSERT/UPDATE/DELETE 的“查询”或“命令”?

PHP MYSQL UPDATE 如果存在或 INSERT 如果不存在?

Postgres UPSERT (INSERT 或 UPDATE) 仅当值不同时

MySQL--INSERT INTO ... ON DUPLICATE KEY UPDATE ...

JAVA:对于UPDATE和INSERT,我可以使用端点或GET请求来处理servlet中的数据