如何使用c#监视SQL Server表更改?

ToD*_*Now 64 c# sql-server monitoring

我有多个应用程序访问同一个数据库,如果其中一个应用程序在某个表中更改了任何内容(更新,插入),我需要收到通知.

数据库和应用程序不在同一台服务器中.

Jar*_*dek 53

你可以使用SqlDependency Class.其预期用途主要用于ASP.NET页面(客户端通知数量较少).

ALTER DATABASE UrDb SET ENABLE_BROKER
Run Code Online (Sandbox Code Playgroud)

实施OnChange事件以获得通知:

void OnChange(object sender, SqlNotificationEventArgs e)
Run Code Online (Sandbox Code Playgroud)

在代码中:

SqlCommand cmd = ...
cmd.Notification = null;

SqlDependency dependency = new SqlDependency(cmd);

dependency.OnChange += OnChange;
Run Code Online (Sandbox Code Playgroud)

它使用Service Broker(基于消息的通信平台)从数据库引擎接收消息.

  • @Kiquenet SB的性能不是问题.但是,查询通知可能会对数据库性能产生重大影响.特别是如果有很多通知(在我的回答中提到).如果是这种情况,您可能最好使用轮询,SOA,... (2认同)

tom*_*ern 35

为了完整性,我认为还有一些其他解决方案比依赖于SqlDependency(和SqlTableDependency)类的解决方案更正统和更完善.SqlDependency是为Web服务器缓存刷新而设计的,因此实际上并没有提供您在事件生成器中需要的负载弹性.

这里还没有提到其他四个选项:

  • 变更跟踪
  • 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)比变更跟踪更强大但成本更高.更改数据捕获将基于监视数据库日志来跟踪和通知更改.因此,CDC可以访问已更改的实际数据,并记录所有个别更改.

与更改跟踪类似,为了在c#中捕获这些更改,必须使用轮询.但是,在CDC的情况下,轮询的信息将包含更改详细信息,因此不一定要回到数据本身.

触发队列

资料来源:https://code.msdn.microsoft.com/Service-Broker-Message-e81c4316

此技术取决于需要通知的表上的触发器.每次更改都将触发一个触发器,触发器会将此信息写入服务代理队列.然后可以使用Service Broker消息处理器(上面链接中的示例)通过C#连接队列.

与更改跟踪或CDC不同,队列触发器不依赖于轮询,从而提供实时事件.

CLR

这是我见过的一种技术,但我不推荐它.依赖于CLR进行外部通信的任何解决方案都是充其量的黑客攻击.CLR旨在通过利用C#使编写复杂的数据处理代码变得更容易.它不是设计用于连接外部依赖项,如消息库.此外,CLR绑定操作可能以不可预测的方式在集群环境中中断.

这就是说,设置起来相当简单,因为您需要做的就是使用CLR注册消息传递程序集,然后您可以使用触发器或SQL作业进行调用.

综上所述...

微软一直坚决拒绝解决这个问题空间,这一直令我感到惊讶.从数据库到代码的事件应该是数据库产品的内置功能.考虑到Oracle Advanced Queuing结合ODP.net MessageAvailable事件为10多年前的 C#提供了可靠的数据库事件,这对MS来说是可悲的.

这样做的结果是,这个问题所列出的解决方案都不是很好.它们都具有技术缺陷并且具有显着的设置成本.微软,如果你正在倾听,请理清这个令人遗憾的事态.

  • 为什么队列触发器已过时? (2认同)

gbn*_*gbn 17

通常,您使用Service Broker

那就是触发器 - >队列 - >应用程序

看到其他答案后编辑:

仅供参考:"查询通知"建立在服务代理上

EDIT2:

更多链接


Chr*_*nco 8

使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)


dya*_*nko 6

使用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);
Run Code Online (Sandbox Code Playgroud)

请点击链接了解详细信息。该组件已在许多企业级应用程序中进行了测试,并被证明是可靠的。希望这可以帮助。

  • 它与Sql Express兼容吗? (2认同)

The*_*rmy 6

SqlDependency不会监视它监视您指定的SqlCommand的数据库,所以如果您试图让值插入1个项目中的数据库并在另一个项目中捕获该事件它将无法工作,因为该事件来自SqlCommand 1º项目不是数据库,因为在创建SqlDependency时,您将其链接到SqlCommand,并且只有在使用该项目的命令时才会创建Change事件.

  • 这实际上并不正确.即使您在Management Studio中插入值,SqlDependency也能正常工作.但是这个类有许多问题,比如内存泄漏.请参阅下面的答案了解详情.@KayLee (4认同)

Chr*_*lor 5

从 SQL Server 2005 开始,您可以选择使用Query Notifications,ADO.NET 可以利用它,请参阅 http://msdn.microsoft.com/en-us/library/t9x04ed2.aspx