[創意料理] 有一個工具可以讓資料庫的資料在發生 Insert、Update、Delete 時即時主動通知我們

發現一個工具 - SqlTableDependency,透過它可以在資料庫的資料發生 Insert、Update、Delete 的時候,即時主動發送通知,而且包含異動後的資料都一起隨著通知發送出來,我們就來看看它要怎麼用?

這個連結裡面有介紹 SqlTableDependency 是如何運作的?它利用了原本 SQL Server 就有的功能,來動態地產生通知機制。

開啟 Service Broker 功能

SqlTableDependency 相依於 SQL Server 的 Service Broker 功能,將訊息透過 Service Broker 廣播給訂閱者,執行下面的指令就可以開啟 Service Broker 功能。

ALTER DATABASE MyDatabase SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE
附加 WITH ROLLBACK IMMEDIATE 選項來執行 ALTER DATABASE 指令,會讓所有未完成的交易都會回復,而且資料庫的任何其他連接都會立即中斷,要附加這個選項是因為開啟 Service Broker 功能必須要在沒有其他使用者在使用的時候,所以請選定良辰吉日再來做這件事。

準備測試資料

我事先在資料庫建立了一個資料表 MyDependencyTalbe,裡面有三個欄位 IdNameDescription

裡面預先加入三筆資料

剩下的交給 SqlTableDependency

我們必須要建立一個與資料表相對應的類別,但是這個類別的名稱及裡面的屬性名稱不一定要跟資料表的名稱及欄位名稱相對應,沒有相對應的部分我們可以透過附加 Data Annotations 或是建立 ModelToTableMapper<T> 的方式來做對應。

但是如果我們的類別名稱及屬性名稱是跟資料表的名稱及欄位名稱相對應的話,就不用做這些事囉。

接著我們就建立一個 SqlTableDependency 的 instance,指定 OnChanged 的事件,呼叫 Start() 方法,就大功告成了。

SqlTableDependency<MyDependencyTable> myDependencyTableDependency;

myDependencyTableDependency = new SqlTableDependency<MyDependencyTable>(ConnectionString);

myDependencyTableDependency.OnChanged += (o, args) => this.OutputNotification(args.ChangeType, args.Entity);

myDependencyTableDependency.Start();

執行結果

沒有銀子彈

在實測的過程中,發現有兩件事情要跟大家分享:

  1. 之前有介紹過在 C# 用 SqlBulkCopy 批次 Insert 大量資料,SqlBulkCopy 在 SQL Server 是用 bcp Utility(bulk copy program Utility)在寫入資料的,根本就沒有生成 Insert 的 SQL 語句,這部分 SqlTableDependency 就通知不到。
  2. 效能大大他有點問題,SqlTableDependency 在少量資料異動的運作上看起來速度還可以接受,但是如果資料量大的話就不能接受了,給大家一個參考的數據,在雙核、4GB RAM、Windows Server 2012 R2、SQL Server 2016 SP1 的 VM 上,刪除 1000 筆資料要 1 秒多,我再試著刪除十萬筆資料,3 分鐘刪不完。

如果我們每次 commit 的資料量不是那麼大的時候,SqlTableDependency 的確可以幫我們不少忙,例如:在資料異動後有需要更新 Cache 時…,但是每次 commit 的資料量大的時候,就不太適合,各位朋友如果要使用的話,要多多評估。

參考資料

 < Source Code >

相關資源

C# 指南
ASP.NET 教學
ASP.NET MVC 指引
Azure SQL Database 教學
SQL Server 教學
Xamarin.Forms 教學