如何使用c#监视SQL Server表更改?
我有多个应用程序访问相同的数据库,如果其中一个应用程序在某个表中更改了任何内容(更新,插入),我需要得到通知。
数据库和应用程序不在同一台服务器上。
您可以使用SqlDependency Class
。 其预期用途主要用于ASP.NET页面(客户端通知数量较less)。
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
(基于消息的通信平台)从数据库引擎接收消息。
一般来说,你会使用Service Broker
这是触发器 – >队列 – >应用程序(S)
编辑后,看到其他答案:
仅供参考:“查询通知”build立在服务代理上
EDIT2:
更多链接
- 事件通知/服务代理
- Service Broker团队
SqlDependency不会监视你所指定的SqlCommand所监视的数据库,所以如果你试图让一个项目中的数据插入到数据库中,并在另一个项目中捕获这个事件,它将无法工作,因为事件是从SqlCommand 1º项目不是数据库,因为当您创build一个SqlDependency时,您将它链接到一个SqlCommand,并且只有当使用该项目的命令时才会创build一个Change事件。
自SQL Server 2005以来,您可以select使用查询通知 ,ADO.NET可以利用查询通知 ,请参阅http://msdn.microsoft.com/zh-cn/library/t9x04ed2.aspx
小心使用SqlDependency类 – 它有内存泄漏的问题 。 但是,您可以使用自己的实现与DDL触发器和SQL Service Broker API或使用开源项目之一,例如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);
希望这可以帮助。
看起来像坏的build筑一路。 你也没有指定你需要通知的应用程序的types(networking应用程序/控制台应用程序/ winforms /服务等)
尽pipe如此,要回答你的问题,解决这个问题有多种方法。 你可以使用:
1)时间戳,如果你只是有兴趣确保从第二个应用程序的下一组更新不冲突从第一个应用程序的更新
2)sql依赖对象 – 请参阅http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency.aspx获取更多信息;
3)多个客户端(web / winform / service)可以订阅并获得更改通知的自定义推送通知服务
简而言之,您需要根据您的通知要求的复杂程度以及您需要使用它们的目的,使用最简单,最简单,最便宜的(根据努力)解决scheme。 不要试图build立一个过于复杂的通知系统,如果一个简单的数据并发是你唯一的要求(在这种情况下去一个简单的时间戳为基础的解决scheme)
使用SqlTableDependency。 当logging发生变化时,这是ac#组件升级事件。 你可以在https://github.com/christiandelbianco/monitor-table-change-with-sqltabledependencyfind其他的细节。;
它类似于.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); } }
为了完整性,在我看来,还有其他一些解决scheme比依赖于SqlDependency(和SqlTableDependency)类的解决scheme更为正统和完善。 SqlDependency是为Web服务器高速caching刷新而devise的,因此并不真正提供负载下的弹性,您可以从事件生产者那里获得这种弹性。
这里还有其他四个选项,
- 更改跟踪
- CDC
- 触发队列
- CLR
更改跟踪
源: https : //docs.microsoft.com/en-us/sql/relational-databases/track-changes/about-change-tracking-sql-server
更改跟踪是SQL Server中的轻量级通知机制。 基本上,数据库范围的版本号随着对数据的每一个改变而递增。 然后将版本号用包含被更改的列的名称的位掩码写入到更改跟踪表中。 请注意,实际更改不会持久。 通知只包含特定数据实体已更改的信息。 此外,由于更改表版本控制是累积的,所以个别更改不会保留,并会被更新的更改覆盖。 这意味着如果实体更改两次,更改跟踪将只知道最近的更改。
为了在C#中捕获这些更改,必须使用轮询。 可以轮询更改表并检查每个更改以查看是否有兴趣。 如果感兴趣,则需要直接转到数据来检索当前状态。
更改数据捕获
源: https : //technet.microsoft.com/en-us/library/bb522489(v=sql.105).aspx
更改数据捕获(CDC)function更强大,但比更改跟踪成本更高。 更改数据捕获将根据监控数据库日志来跟踪和通知更改。 因为这个CDC可以访问已经被更改的实际数据,并logging所有的个人变化。
与更改跟踪类似,为了在C#中捕获这些更改,必须使用轮询。 但是,在CDC的情况下,所轮询的信息将包含更改细节,因此不一定要回到数据本身。
触发队列
资料来源: https : //code.msdn.microsoft.com/Service-Broker-Message-e81c4316
这种技术依赖于需要通知的表上的触发器。 每次更改都会触发一个触发器,触发器会将这些信息写入服务代理队列。 然后可以使用Service Broker消息处理器(在上面的链接中的示例)通过C#连接队列。
与更改跟踪或CDC不同,触发队列不依赖于轮询,从而提供实时事件。
CLR
这是我见过的一种技术,但我不会推荐它。 依靠CLR进行外部通信的任何解决scheme都是最好的。 CLR旨在通过利用C#来简化写入复杂的数据处理代码。 它没有被devise为连接像消息传递库这样的外部依赖。 而且,CLR绑定操作可能以不可预知的方式在群集环境中崩溃。
这就是说,设置起来非常简单,因为您只需要使用CLR注册消息传递程序集,然后就可以使用触发器或SQL作业调用。
综上所述…
微软一直坚决拒绝解决这个问题,这一直令我惊讶。 从数据库到代码的事件应该是数据库产品的内置function。 考虑到Oracle高级队列与ODP.net MessageAvailable事件相结合提供了可靠的数据库事件到C#超过10年前 ,这是从MS悲伤。
结果是,这个问题列出的解决scheme都不是很好。 他们都有技术上的缺点,而且安装成本很高。 MS,如果你正在听,请理清这种情况。
另一个非常简单的监控表的方式是表版本控制。 该系统已经被certificate在诸如DNS同步之类的结构中工作。 为了使它工作,你创build一个包含表名和表格版本的表,如decimal
或bigint.
在您需要监控的每个表中,创build触发器插入,更新和删除操作时会在版本控制表中递增适当的表版本。 如果您期望经常更改任何受监视的表,则需要设置版本重用。 最后,在你的应用程序中,每当你查询受监视的表时,你也查询它的版本并存储它。 当您从应用程序中更改受监视的表格时,首先查询其当前版本并仅在版本不变的情况下处理更改。 你可以在SQL服务器上存储过程为你工作。 这是非常简单但经过validation的可靠解决scheme 它具有特定的function用途(确保数据的一致性),并且对资源(不会引发不值得注意的中介事件)更为敏感,但需要应用程序主动检查更改,而不是被动地等待事件发生。