Programing

C #을 사용하여 SQL Server 테이블 변경을 모니터링하는 방법은 무엇입니까?

crosscheck 2020. 11. 24. 07:39
반응형

C #을 사용하여 SQL Server 테이블 변경을 모니터링하는 방법은 무엇입니까?


동일한 DB에 액세스하는 애플리케이션이 두 개 이상 있으며 이러한 앱 중 하나가 특정 테이블에서 변경 (업데이트, 삽입)하면 알림을 받아야합니다.

데이터베이스와 앱이 동일한 서버에 없습니다.


당신은을 사용할 수 있습니다 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는 웹 서버 캐시 새로 고침을 위해 설계되었으므로 실제로 이벤트 생성자에게 필요한로드시 탄력성을 제공하지 않습니다.

여기에 아직 언급되지 않은 다른 네 가지 옵션이 있습니다.

  • 변경 추적
  • 질병 통제 예방 센터
  • 대기열에 대한 트리거
  • 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 작업을 사용하여 호출 할 수 있으므로 설정이 매우 간단합니다.

요약해서 말하자면...

마이크로 소프트가이 문제 영역의 해결을 꾸준히 거부 해 온 것은 항상 저에게 놀랍습니다. 데이터베이스에서 코드로의 이벤트는 데이터베이스 제품의 기본 제공 기능이어야합니다. ODP.net MessageAvailable 이벤트 와 결합 된 Oracle Advanced Queuing 10 년 이상 전에 C #에 신뢰할 수있는 데이터베이스 이벤트를 제공 했다는 점을 고려할 때 MS에게는 안타까운 일입니다.

이것의 결론은이 질문에 나열된 솔루션 중 어느 것도 매우 훌륭하지 않다는 것입니다. 그들은 모두 기술적 단점이 있고 상당한 설치 비용이 있습니다. 마이크로 소프트가 듣고 있다면이 미안한 상황을 정리해주세요.


일반적으로 Service Broker를 사용합니다.

그것은 트리거-> 대기열-> 응용 프로그램입니다.

다른 답변을 본 후 편집 :

참고 : "쿼리 알림"은 Service Broker를 기반으로합니다.

편집 2 :

더 많은 링크


SqlTableDependency를 사용하십시오. 레코드가 변경 될 때 이벤트를 발생시키는 ac # 구성 요소입니다. https://github.com/christiandelbianco/monitor-table-change-with-sqltabledependency 에서 다른 세부 정보를 찾을 수 있습니다.

SqlTableDependency가 수정 / 삭제 또는 업데이트 된 데이터베이스 테이블 값을 포함하는 이벤트를 발생 시킨다는 점을 제외하면 .NET SqlDependency와 유사합니다.

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 doesn't watch the database it watches the SqlCommand you specify so if you are trying to lets say insert values into the database in 1 project and capture that event in another project it won't work because the event was from the SqlCommand from the 1º project not the database because when you create an SqlDependency you link it to a SqlCommand and only when that command from that project is used does it create a Change event.


Be careful using SqlDependency class - it has problems with memory leaks.

Just use a cross-platform, .NET 3.5, .NET Core compatible and open source solution - SqlDependencyEx. You can get notifications as well as data that was changed (you can access it through properties in notification event object). You can also tack DELETE\UPDATE\INSERT operations separately or together.

Here is an example of how easy it is to use 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);

Please follow the links for details. This component was tested in many enterprise-level applications and proven to be reliable. Hope this helps.


Since SQL Server 2005 you have the option of using Query Notifications, which can be leveraged by ADO.NET see http://msdn.microsoft.com/en-us/library/t9x04ed2.aspx


looks like bad architecture all the way. also you have not specified the type of app you need to notify to (web app / console app / winforms / service etc etc)

nevertheless, to answer your question, there are multiple ways of solving this. you could use:

1) timestamps if you were just interested in ensuring the next set of updates from the second app dont conflict with the updates from the first app

2) sql dependency object - see http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency.aspx for more info

3) a custom push notification service which multiple clients (web / winform / service) can subscribe to and get notified on changes

in short, you need to use the simplest and easiest and cheapest (in terms of efforts) solution based on how complex your notification requirements are and for what purpose you need to use them. dont try to build an overly complex notification system if a simple data concurrency is your only requirement (in that case go for a simple timestamp based solution)


Another, very simple way of monitoring tables is table versioning. The system is proven working in constructions such as DNS synchronization. To make it work you create a table containing table names and table versions as decimal or bigint.In each table that you need monitored, create trigger on insert, update and delete that will increment appropriate table version in versioning table when executed. If you expect any of the monitored tables to be altered often, you need to provision for version reusing. Finally, in your application, every time you query monitored table, you also query its version and store it. When you go to alter the monitored table from your app, you first query its current version and process the change only if the version is unchanged. You can have stored proc on sql server do that work for you. This is extremely simple but proven solid solution. It has specific functional use (to ensure data consistency) and is light on resources (you do not raise brokered events that you would not watch for) but needs application to actively check for changes rather than passively wait for event to happen.

참고URL : https://stackoverflow.com/questions/5288434/how-to-monitor-sql-server-table-changes-by-using-c

반응형