Làm thế nào để giám sát các thay đổi của bảng SQL Server bằng cách sử dụng c #?


77

Tôi có nhiều ứng dụng truy cập vào cùng một DB và tôi cần được thông báo nếu một trong những ứng dụng này thay đổi bất kỳ điều gì (cập nhật, chèn) trong một bảng nhất định.

Cơ sở dữ liệu và ứng dụng không nằm trong cùng một máy chủ.


4
Bạn cần loại thông báo nào? Ngay tức khắc? Bạn cần một ứng dụng được thông báo hay bạn cần một email được gửi cho bạn? Bạn thực sự cần được thông báo hay bạn chỉ muốn theo dõi những thay đổi này?
richard

7
Bạn có thể muốn tiếp tục ở lại lần sau sau khi đặt câu hỏi để có thể làm rõ / tương tác với người trả lời. VẬY người dùng rất nhanh với câu trả lời và bạn đang lãng phí cơ hội tốt để nhận được câu trả lời tốt nếu bạn không "di chuột" qua câu hỏi của mình để chờ trả lời.
richard

Tôi chỉ cần biết nếu có bất kỳ bản cập nhật ứng dụng nào khác hoặc chèn bất kỳ dữ liệu nào, tôi không cần bản thân dữ liệu, chỉ là một lá cờ cho biết bảng này có những thay đổi mới. xin lỗi vì đến trễ i didnt biết rằng câu trả lời là nhanh như vậy
ToDayIsNow

Câu trả lời:


55

Bạn có thể sử dụng SqlDependency Class. Mục đích sử dụng của nó chủ yếu dành cho các trang ASP.NET (số lượng thông báo khách hàng thấp).

ALTER DATABASE UrDb SET ENABLE_BROKER

Triển khai OnChangesự kiện để nhận thông báo:

void OnChange(object sender, SqlNotificationEventArgs e)

Và trong mã:

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

SqlDependency dependency = new SqlDependency(cmd);

dependency.OnChange += OnChange;

Nó sử dụng Service Broker(một nền tảng giao tiếp dựa trên tin nhắn) để nhận tin nhắn từ cơ sở dữ liệu.


@jaroslav jandek, Chào bạn. Bạn có biết cách khác ngoại trừ sqldependency không? Tôi có vấn đề với sqldependency vì nó có rất nhiều hạn chế như OUTER JOIN; mà tôi sử dụng trong hầu hết các truy vấn sql của mình!
M_Mogharrabi

@M_Mogharrabi Các thông báo được thực hiện bằng cách sử dụng lập chỉ mục không thể sử dụng với các liên kết bên ngoài. Bạn sẽ phải thực hiện các phép nối của mình theo cách thủ công với các phép nối bên ngoài dưới dạng các truy vấn riêng biệt. Tôi sẽ cố gắng tránh điều này trong hầu hết các trường hợp.
Jaroslav Jandek

2
@Kiquenet Hiệu suất của SB không phải là vấn đề ở đây. Tuy nhiên, Thông báo truy vấn có thể có tác động đáng kể đến hiệu suất DB. Đặc biệt nếu có nhiều thông báo (được đề cập trong câu trả lời của tôi). Nếu đúng như vậy, bạn có thể được tốt hơn off với bỏ phiếu, SOA, ...
Jaroslav Jandek

Tôi đã sử dụng SqlSependency để kích hoạt các thay đổi cơ sở dữ liệu để hiển thị thông báo đẩy cho ứng dụng khách nhưng gần đây chúng tôi đã chuyển sang SQL Azure và nó không hỗ trợ, SqlSependencyvậy có cách nào tốt hơn cách này để nhận thông báo khi dữ liệu SQL Azure thay đổi hoặc khi dữ liệu mới được chèn vào không?
Shaiju T

1
@stom không có thay thế, AFAIK. Nếu bạn kiểm soát sự xâm nhập dữ liệu bạn có thể dễ dàng thông báo bằng cách sử dụng công nghệ SignalR hoặc tương tự ...
Jaroslav Jandek

45

Vì lợi ích của sự hoàn chỉnh, có một số giải pháp khác (theo ý kiến ​​của tôi) chính thống hơn các giải pháp dựa trên các lớp SqlDependency (và SqlTableDependency). SqlDependency ban đầu được thiết kế để làm mới các bộ nhớ cache của máy chủ web phân tán dễ dàng hơn và do đó, nó được xây dựng theo một nhóm yêu cầu khác so với nếu nó được thiết kế như một nhà sản xuất sự kiện.

Có bốn lựa chọn rộng rãi, một số trong số đó chưa được đề cập ở đây:

  • Thay đổi theo dõi
  • CDC
  • Kích hoạt hàng đợi
  • CLR

Thay đổi theo dõi

Nguồn: https://docs.microsoft.com/en-us/sql/relational-databases/track-changes/about-change-tracking-sql-server

Theo dõi thay đổi là một cơ chế thông báo nhẹ trong máy chủ SQL. Về cơ bản, số phiên bản trên toàn cơ sở dữ liệu được tăng lên với mỗi thay đổi đối với bất kỳ dữ liệu nào. Sau đó, số phiên bản được ghi vào bảng theo dõi thay đổi với mặt nạ bit bao gồm tên của các cột đã được thay đổi. Lưu ý, thay đổi thực tế không được duy trì. Thông báo chỉ chứa thông tin mà một thực thể dữ liệu cụ thể đã thay đổi. Hơn nữa, bởi vì việc lập phiên bản bảng thay đổi là tích lũy, thông báo thay đổi trên các mục riêng lẻ sẽ không được lưu giữ và bị ghi đè bởi các thông báo mới hơn. Điều này có nghĩa là nếu một thực thể thay đổi hai lần, theo dõi thay đổi sẽ chỉ biết về thay đổi gần đây nhất.

Để nắm bắt những thay đổi này trong c #, phải sử dụng tính năng thăm dò. Các bảng theo dõi thay đổi có thể được thăm dò ý kiến ​​và kiểm tra từng thay đổi để xem liệu có đáng quan tâm hay không. Nếu quan tâm, cần thiết sau đó trực tiếp vào dữ liệu để lấy lại trạng thái hiện tại.

Thay đổi thu thập dữ liệu

Nguồn: https://technet.microsoft.com/en-us/library/bb522489(v=sql.105).aspx

Thu thập dữ liệu thay đổi (CDC) mạnh hơn nhưng tốn kém nhất so với theo dõi thay đổi. Việc nắm bắt dữ liệu thay đổi sẽ theo dõi và thông báo các thay đổi dựa trên việc theo dõi nhật ký cơ sở dữ liệu. Vì điều này CDC có quyền truy cập vào dữ liệu thực tế đã được thay đổi và lưu giữ hồ sơ về tất cả các thay đổi riêng lẻ.

Tương tự để theo dõi thay đổi, để nắm bắt những thay đổi này trong c #, phải sử dụng tính năng thăm dò. Tuy nhiên, trong trường hợp CDC, thông tin được thăm dò ý kiến ​​sẽ chứa các chi tiết thay đổi, vì vậy không cần thiết phải quay lại chính dữ liệu đó.

Kích hoạt hàng đợi

Nguồn: https://code.msdn.microsoft.com/Service-Broker-Message-e81c4316

Kỹ thuật này phụ thuộc vào trình kích hoạt trên bảng mà từ đó thông báo được yêu cầu. Mỗi thay đổi sẽ kích hoạt một trình kích hoạt và trình kích hoạt sẽ ghi thông tin này vào hàng đợi của nhà môi giới dịch vụ. Sau đó, hàng đợi có thể được kết nối qua C # bằng Trình xử lý thông báo của nhà môi giới dịch vụ (ví dụ trong liên kết ở trên).

Không giống như theo dõi thay đổi hoặc CDC, trình kích hoạt hàng đợi không phụ thuộc vào việc thăm dò ý kiến ​​và do đó cung cấp sự kiện thời gian thực.

CLR

Đây là một kỹ thuật tôi đã thấy được sử dụng, nhưng tôi không khuyến khích nó. Bất kỳ giải pháp nào dựa vào CLR để giao tiếp với bên ngoài là tốt nhất. CLR được thiết kế để giúp viết mã xử lý dữ liệu phức tạp dễ dàng hơn bằng cách tận dụng C #. Nó không được thiết kế để nối các phụ thuộc bên ngoài như thư viện nhắn tin. Hơn nữa, các hoạt động ràng buộc CLR có thể bị phá vỡ trong môi trường nhóm theo những cách không thể đoán trước.

Điều này nói rằng, việc thiết lập khá đơn giản, vì tất cả những gì bạn cần làm là đăng ký lắp ráp nhắn tin với CLR và sau đó bạn có thể gọi đi bằng cách sử dụng trình kích hoạt hoặc lệnh SQL.

Tóm tắt...

Tôi luôn thấy ngạc nhiên khi Microsoft kiên quyết từ chối giải quyết vấn đề này. Sự kiện từ cơ sở dữ liệu sang mã phải là một tính năng được tích hợp sẵn của sản phẩm cơ sở dữ liệu. Xem xét rằng Oracle Advanced Queuing kết hợp với sự kiện ODP.net MessageAvailable đã cung cấp sự kiện cơ sở dữ liệu đáng tin cậy cho C # hơn 10 năm trước , điều này thật tồi tệ với MS.

Kết quả của việc này là không có giải pháp nào được liệt kê cho câu hỏi này là rất tốt. Tất cả chúng đều có nhược điểm kỹ thuật và có chi phí thiết lập đáng kể. Microsoft nếu bạn đang lắng nghe, vui lòng giải quyết tình trạng xin lỗi này.


17

Nói chung, bạn sẽ sử dụng Service Broker

Đó là trình kích hoạt -> hàng đợi -> (các) ứng dụng

Chỉnh sửa, sau khi xem các câu trả lời khác:

FYI: "Thông báo truy vấn" được xây dựng trên Nhà môi giới dịch vụ

Chỉnh sửa2:

Liên kết khác


Tôi đã sử dụng SqlSependency để kích hoạt các thay đổi cơ sở dữ liệu để hiển thị thông báo đẩy cho ứng dụng khách nhưng gần đây chúng tôi đã chuyển sang SQL Azure và nó không hỗ trợ, SqlSependencyvậy có cách nào tốt hơn cách này để nhận thông báo khi dữ liệu SQL Azure thay đổi hoặc khi dữ liệu mới được chèn vào không?
Shaiju T

8

Sử dụng SqlTableDependency. Nó là sự kiện nâng cao thành phần ac # khi bản ghi thay đổi. Bạn có thể tìm chi tiết những người khác tại: https://github.com/christiandelbianco/monitor-table-change-with-sqltabledependency

Nó tương tự với .NET SqlDependency ngoại trừ SqlTableDependency nâng cao các sự kiện có chứa các giá trị bảng cơ sở dữ liệu đã sửa đổi / xóa hoặc cập nhật:

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);
    }
}

7

Hãy cẩn thận khi sử dụng lớp SqlDependency - nó có vấn đề về rò rỉ bộ nhớ.

Chỉ cần sử dụng giải pháp mã nguồn mở và tương thích .NET 3.5, .NET Core đa nền tảng - SqlDependencyEx . Bạn có thể nhận thông báo cũng như dữ liệu đã được thay đổi (bạn có thể truy cập thông qua các thuộc tính trong đối tượng sự kiện thông báo). Bạn cũng có thể giải quyết các thao tác DELETE \ UPDATE \ INSERT riêng biệt hoặc cùng nhau.

Đây là một ví dụ về cách dễ dàng sử dụng 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);

Vui lòng làm theo các liên kết để biết chi tiết. Thành phần này đã được thử nghiệm trong nhiều ứng dụng cấp doanh nghiệp và được chứng minh là đáng tin cậy. Hi vọng điêu nay co ich.


2
Nó có tương thích với Sql Express không?
dmigo

Chắc chắn, nó là tương thích
dyatchenko

6

SqlDependency không theo dõi cơ sở dữ liệu mà nó theo dõi SqlCommand mà bạn chỉ định, vì vậy nếu bạn đang cố cho phép chèn giá trị vào cơ sở dữ liệu trong 1 dự án và nắm bắt sự kiện đó trong một dự án khác, nó sẽ không hoạt động vì sự kiện là từ SqlCommand từ 1º dự án không phải cơ sở dữ liệu bởi vì khi bạn tạo một SqlDependency, bạn liên kết nó với một SqlCommand và chỉ khi lệnh đó từ dự án đó được sử dụng thì nó mới tạo ra một sự kiện Thay đổi.


4
Điều này không thực sự chính xác. SqlDependency hoạt động ngay cả khi bạn chèn các giá trị trong Management Studio. Tuy nhiên lớp này có rất nhiều vấn đề như rò rỉ bộ nhớ. Xem câu trả lời của tôi bên dưới để biết chi tiết. @KayLee
dyatchenko

@dyatchenko, cảm ơn ý kiến ​​của bạn. Tôi đang sử dụng SqlTableDependency được đề cập ở một câu trả lời của bài đăng này. Tôi rất bận rộn bây giờ nhưng sẽ có một cái nhìn tại vấn đề bộ nhớ sau đó, tất nhiên ...
Kay Lee


2

trông giống như kiến ​​trúc xấu tất cả các cách. Ngoài ra, bạn chưa chỉ định loại ứng dụng bạn cần thông báo (ứng dụng web / ứng dụng bảng điều khiển / winforms / dịch vụ, v.v.)

Tuy nhiên, để trả lời câu hỏi của bạn, có nhiều cách để giải quyết vấn đề này. bạn đã có thể sử dụng:

1) dấu thời gian nếu bạn chỉ quan tâm đến việc đảm bảo tập hợp các bản cập nhật tiếp theo từ ứng dụng thứ hai không xung đột với các bản cập nhật từ ứng dụng đầu tiên

2) đối tượng phụ thuộc sql - xem http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency.aspx để biết thêm thông tin

3) dịch vụ thông báo đẩy tùy chỉnh mà nhiều khách hàng (web / winform / dịch vụ) có thể đăng ký và nhận thông báo về các thay đổi

Nói tóm lại, bạn cần sử dụng giải pháp đơn giản nhất, dễ dàng nhất và rẻ nhất (về mặt nỗ lực) dựa trên mức độ phức tạp của các yêu cầu thông báo và mục đích bạn cần sử dụng chúng. không cố gắng xây dựng một hệ thống thông báo quá phức tạp nếu dữ liệu đơn giản đồng thời là yêu cầu duy nhất của bạn (trong trường hợp đó, hãy sử dụng giải pháp dựa trên dấu thời gian đơn giản)


19
Chỉ vì tò mò, bạn có thể làm rõ "kiến trúc xấu" ở đây là gì không?
James

1

Một cách khác, rất đơn giản để giám sát bảng là lập phiên bản bảng. Hệ thống đã được chứng minh hoạt động trong các cấu trúc như đồng bộ hóa DNS. Để làm cho nó hoạt động, bạn tạo một bảng chứa tên bảng và phiên bản bảng dưới dạng decimalhoặcbigint.Trong mỗi bảng mà bạn cần theo dõi, hãy tạo trình kích hoạt khi chèn, cập nhật và xóa sẽ tăng phiên bản bảng thích hợp trong bảng lập phiên bản khi được thực thi. Nếu bạn mong đợi bất kỳ bảng được giám sát nào thường xuyên bị thay đổi, bạn cần cung cấp cho việc sử dụng lại phiên bản. Cuối cùng, trong ứng dụng của bạn, mỗi khi bạn truy vấn bảng được giám sát, bạn cũng truy vấn phiên bản của nó và lưu trữ nó. Khi bạn thay đổi bảng được giám sát từ ứng dụng của mình, trước tiên bạn truy vấn phiên bản hiện tại của nó và chỉ xử lý thay đổi nếu phiên bản không thay đổi. Bạn có thể đã lưu trữ proc trên máy chủ sql làm việc đó cho bạn. Đây là giải pháp cực kỳ đơn giản nhưng đã được chứng minh.


Tôi nghĩ rằng điều này sẽ tạo ra một nút thắt cổ chai khóa xung quanh hàng chứa phiên bản cho một bảng nhất định.
Dan Def

0

Đây không phải là một thông báo chính xác nhưng trong tiêu đề bạn nói màn hình và điều này có thể phù hợp với tình huống đó.

Sử dụng cột dấu thời gian của SQL Server có thể cho phép bạn dễ dàng xem bất kỳ thay đổi nào (vẫn tồn tại) giữa các truy vấn.

Theo ý kiến ​​của tôi, kiểu cột dấu thời gian của SQL Server được đặt tên không hợp lý vì nó không liên quan đến thời gian, nó là một giá trị rộng của cơ sở dữ liệu tự động tăng lên khi chèn hoặc cập nhật. Bạn có thể chọn Max (dấu thời gian) trong bảng bạn đang theo dõi hoặc trả lại dấu thời gian từ hàng bạn vừa chèn, sau đó chỉ cần chọn nơi dấu thời gian> lưu trữ Dấu thời gian, điều này sẽ cung cấp cho bạn tất cả các kết quả đã được cập nhật hoặc chèn giữa các thời điểm đó.

Vì đó là một giá trị rộng của cơ sở dữ liệu, bạn có thể sử dụng dấu thời gian được lưu trữ của mình để kiểm tra bất kỳ bảng nào đã có dữ liệu được ghi vào nó kể từ lần cuối bạn kiểm tra / cập nhật dấu thời gian được lưu trữ của mình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.