我有多个应用程序正在访问同一数据库,并且如果这些应用程序之一更改了某个表中的任何内容(更新,插入),我需要得到通知。
数据库和应用程序不在同一服务器上。
我有多个应用程序正在访问同一数据库,并且如果这些应用程序之一更改了某个表中的任何内容(更新,插入),我需要得到通知。
数据库和应用程序不在同一服务器上。
Answers:
您可以使用SqlDependency Class
。它的预期用途主要是用于ASP.NET页(客户端通知数量少)。
ALTER DATABASE UrDb SET ENABLE_BROKER
实施OnChange
事件以获取通知:
void OnChange(object sender, SqlNotificationEventArgs e)
并在代码中:
SqlCommand cmd = ...
cmd.Notification = null;
SqlDependency dependency = new SqlDependency(cmd);
dependency.OnChange += OnChange;
它使用Service Broker
(基于消息的通信平台)从数据库引擎接收消息。
为了完整性起见,还有其他一些解决方案(在我看来)比依赖SqlDependency(和SqlTableDependency)类的解决方案更为传统。SqlDependency最初旨在使刷新分布式Web服务器缓存更加容易,因此,与被设计为事件生产者相比,它是根据一组不同的要求构建的。
大致有四个选项,其中一些尚未在此处讨论:
变更追踪
更改跟踪是SQL Server中的一种轻量级通知机制。基本上,数据库范围内的版本号会随着对任何数据的每次更改而增加。然后使用位掩码(包括已更改列的名称)将版本号写入更改跟踪表。请注意,实际更改不会保留。该通知仅包含特定数据实体已更改的信息。此外,由于变更表的版本控制是累积性的,因此不会保留有关单个项目的变更通知,并由较新的通知覆盖。这意味着,如果实体更改两次,更改跟踪将仅知道最新更改。
为了捕获c#中的这些更改,必须使用轮询。可以查询变更跟踪表,并检查每个变更是否感兴趣。如果有兴趣,则有必要直接转到数据以检索当前状态。
更改数据捕获
资源: https //technet.microsoft.com/en-us/library/bb522489(v=sql.105).aspx
变更数据捕获(CDC)比变更跟踪功能更强大,但成本最高。更改数据捕获将基于监视数据库日志来跟踪并通知更改。因此,CDC可以访问已更改的实际数据,并保留所有单独更改的记录。
与更改跟踪类似,为了捕获c#中的这些更改,必须使用轮询。但是,在CDC的情况下,轮询的信息将包含更改详细信息,因此严格地不必返回数据本身。
触发队列
来源:https : //code.msdn.microsoft.com/Service-Broker-Message-e81c4316
此技术取决于需要通知的表上的触发器。每次更改都会触发一个触发器,并且触发器会将此信息写入服务代理队列。然后,可以使用Service Broker消息处理器(以上链接中的示例)通过C#将队列连接到该队列。
与变更跟踪或CDC不同,队列触发不依赖于轮询,从而提供了实时事件。
CLR
这是我见过的一种技术,但我不推荐使用。任何依赖CLR进行外部通信的解决方案充其量都是hack。CLR旨在通过利用C#简化编写复杂数据处理代码的过程。它并非旨在连接外部依赖项(例如消息传递库)。此外,CLR绑定的操作可能会以无法预测的方式在群集环境中中断。
这就是说,设置非常简单,因为您要做的就是向CLR注册消息传递程序集,然后可以使用触发器或SQL作业取消调用。
综上所述...
微软一直坚决拒绝解决这一问题,这一直令我感到惊讶。从数据库到代码的事件应该是数据库产品的内置功能。考虑到Oracle Advanced Queuing与ODP.net MessageAvailable事件相结合已为10年前的C#提供了可靠的数据库事件,这对MS来说是可悲的。
这样做的结果是,这个问题列出的解决方案都不是很好。它们都具有技术缺陷,并且安装成本很高。Microsoft,如果您正在听,请解决这种抱歉的情况。
使用SqlTableDependency。记录更改时,这是ac#组件引发事件。您可以在以下位置找到其他详细信息: https //github.com/christiandelbianco/monitor-table-change-with-sqltabledependency
它与.NET SqlDependency类似,除了SqlTableDependency引发包含已修改/删除或更新的数据库表值的事件:
string conString = "data source=.;initial catalog=myDB;integrated security=True";
using(var tableDependency = new SqlTableDependency<Customers>(conString))
{
tableDependency.OnChanged += TableDependency_Changed;
tableDependency.Start();
Console.WriteLine("Waiting for receiving notifications...");
Console.WriteLine("Press a key to stop");
Console.ReadKey();
}
...
...
void TableDependency_Changed(object sender, RecordChangedEventArgs<Customers> e)
{
if (e.ChangeType != ChangeType.None)
{
var changedEntity = e.Entity;
Console.WriteLine("DML operation: " + e.ChangeType);
Console.WriteLine("ID: " + changedEntity.Id);
Console.WriteLine("Name: " + changedEntity.Name);
Console.WriteLine("Surname: " + changedEntity.Surname);
}
}
使用SqlDependency时要小心类-它有问题内存泄漏。
只需使用跨平台,.NET 3.5,.NET Core兼容的开源解决方案- -SqlDependencyEx。您可以获取通知以及已更改的数据(可以通过通知事件对象中的属性进行访问)。您也可以单独或一起添加DELETE \ UPDATE \ INSERT操作。
这是一个使用SqlDependencyEx多么容易的示例:
int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME))
{
sqlDependency.TableChanged += (o, e) => changesReceived++;
sqlDependency.Start();
// Make table changes.
MakeTableInsertDeleteChanges(changesCount);
// Wait a little bit to receive all changes.
Thread.Sleep(1000);
}
Assert.AreEqual(changesCount, changesReceived);
请点击链接了解详细信息。该组件已在许多企业级应用程序中经过测试,并被证明是可靠的。希望这可以帮助。
SqlDependency不会监视数据库,而是会监视您指定的SqlCommand,因此,如果您试图说在1个项目中向数据库中插入值并在另一个项目中捕获该事件,则该事件将无法正常工作,因为该事件来自SqlCommand。 1º项目不是数据库,因为创建SqlDependency时会将其链接到SqlCommand,并且仅当使用该项目中的命令时,它才会创建Change事件。
从SQL Server 2005开始,您可以选择使用Query Notifications,ADO.NET可以利用它,请参阅 http://msdn.microsoft.com/zh-cn/library/t9x04ed2.aspx
看起来就像是糟糕的架构。另外,您还没有指定需要通知的应用程序类型(Web应用程序/控制台应用程序/ winforms /服务等)
但是,要回答您的问题,有多种解决方法。您可以使用:
1)时间戳记(如果您只是想确保第二个应用程序的下一组更新不会与第一个应用程序的更新冲突)
2)sql依赖项对象-有关更多信息,请参见http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqldependency.aspx
3)定制的推送通知服务,多个客户端(Web / WinForm /服务)可以订阅并获得更改通知
简而言之,您需要根据通知要求的复杂程度以及使用它们的目的来使用最简单,最容易,最便宜(就工作而言)的解决方案。如果仅需要简单的数据并发,则不要尝试构建过于复杂的通知系统(在这种情况下,请使用基于时间戳的简单解决方案)
监视表的另一种非常简单的方法是表版本控制。经验证,该系统可在DNS同步等结构中运行。为了使其正常工作,您需要创建一个包含表名称和表版本的表decimal
或bigint.
在需要监视的每个表中,在插入,更新和删除时创建触发器,这些触发器将在执行时增加版本控制表中的相应表版本。如果您希望任何被监视的表经常更改,则需要准备重新使用版本。最后,在您的应用程序中,每次查询被监视的表时,您还要查询其版本并将其存储。当您从您的应用程序更改受监视的表时,您首先要查询其当前版本并仅在版本未更改的情况下处理更改。您可以将proc存储在sql server上为您工作。这是极其简单但经过验证的可靠解决方案。
这不完全是一个通知,但您在标题中说了“监视”,它可以适应这种情况。
使用“ SQL Server时间戳”列可以使您轻松查看查询之间的任何更改(仍然存在)。
在我看来,SQL Server时间戳记列类型的命名不正确,因为它根本与时间无关,它是数据库范围的值,在任何插入或更新时都会自动递增。您可以在后面的表中选择Max(timestamp),也可以从刚插入的行中返回时间戳,然后选择timestamp> storedTimestamp,这将为您提供在这些时间之间已更新或插入的所有结果。
由于它也是数据库范围的值,因此您也可以使用存储的时间戳来检查自上次检查/更新存储的时间戳以来是否有任何表写入了数据。