다음을 통해 공유


방법: 공동 작업 동기화를 위한 서버 데이터베이스 프로비전(SQL Server 이외)

참고

다른 ADO.NET 호환 데이터베이스 동기화 설명서 섹션의 항목에서는 Sync Framework를 사용하여 SQL Server 이외의 데이터베이스를 동기화하는 방법을 보여 줍니다. 이 릴리스에서는 SQL Server가 코드 예제에 사용되지만 표시되는 SQL Server 관련 개체(예: SqlConnection) 및 SQL 쿼리를 일부 수정하여 코드를 다른 ADO.NET 호환 데이터베이스에 대해 사용할 수 있습니다. SQL Server 동기화에 대한 자세한 내용은 방법: 공동 작업 동기화 구성 및 실행(SQL Server)를 참조하십시오.

이 항목에서는 DbSyncProvider에서 동기화되는 데이터베이스를 프로비전하는 방법에 대해 설명하므로 증분 데이터 변경 내용을 해당 데이터베이스에서 추적할 수 있습니다. 추적되는 변경 내용은 동기화 세션 동안 다른 노드에 적용될 수 있습니다. Sync Framework에 대한 데이터베이스를 프로비전하려면 다음 단계를 수행합니다.

  1. 데이터베이스에 스냅숏 격리를 사용하도록 설정

  2. 동기화할 테이블 식별

  3. 테이블당 메타데이터를 저장할 추적 테이블을 만들고 이러한 테이블에 인덱스 만들기

  4. 각 기본 테이블에 추적 테이블을 채우고 업데이트할 트리거 만들기

  5. (선택 사항) 데이터베이스의 기존 데이터 처리

  6. 범위당 메타데이터를 저장할 추적 테이블을 만들고 이 테이블에 인덱스 만들기

  7. 한 단위로 동기화할 테이블을 지정하는 동기화 범위 정의

  8. 데이터와 메타데이터를 선택하고 업데이트하는 저장 프로시저 만들기

SqlCeSyncProvider에서 동기화되는 데이터베이스의 경우에는 이러한 단계가 필요하지 않습니다. 데이터베이스가 초기화될 때 Sync Framework에서 프로비전을 처리합니다.

데이터베이스를 프로비전한 후 다른 노드와 동기화할 수 있습니다. 동기화를 구성하고 실행하는 방법에 대한 자세한 내용은 방법: 공동 작업 동기화 구성 및 실행(SQL Server 이외)을 참조하십시오.

데이터베이스에 스냅숏 격리를 사용하도록 설정

동기화 세션의 변경 내용 열거 단계를 진행하는 동안 Sync Framework는 스냅숏 격리 상태에서 트랜잭션을 시작합니다. 스냅숏 격리 상태에서 트랜잭션을 시작하려면 다음 코드 예제와 같이 ALLOW_SNAPSHOT_ISOLATION 데이터베이스 옵션을 ON으로 설정해야 합니다.

ALTER DATABASE [database name] SET ALLOW_SNAPSHOT_ISOLATION ON

자세한 내용은 SQL Server 온라인 설명서를 참조하십시오.

동기화할 테이블 식별

데이터베이스를 프로비전하는 첫 번째 단계는 동기화할 테이블을 식별하는 것입니다. 각 테이블에는 기본 키가 있어야 합니다. 다음 코드 예제를 참조하십시오. 이 예제에서는 SyncSamplesDb_Peer1 데이터베이스의 Sales.Customer 테이블 스키마를 보여 줍니다.

CREATE TABLE Sales.Customer(
    CustomerId uniqueidentifier NOT NULL PRIMARY KEY DEFAULT NEWID(), 
    CustomerName nvarchar(100) NOT NULL,
    SalesPerson nvarchar(100) NOT NULL,
    CustomerType nvarchar(100) NOT NULL)

동기화하는 각 테이블에는 연결된 DbSyncAdapter 개체가 있으며 해당 개체의 RowIdColumns 컬렉션에서 기본 키를 지정합니다. 자세한 내용은 방법: 공동 작업 동기화 구성 및 실행(SQL Server 이외)을 참조하십시오.

테이블은 비어 있거나 기존 데이터를 포함할 수 있습니다. 테이블에 동기화해야 하는 기존 데이터 행이 포함되어 있으면 적절한 변경 내용 추적 테이블에 각 행에 대한 메타데이터 항목이 있는지 확인해야 합니다. 자세한 내용은 데이터베이스의 기존 데이터 처리를 참조하십시오.

테이블당 메타데이터에 대한 추적 테이블 만들기

Sync Framework에는 두 노드 간에 이전 동기화 세션 이후 변경된 행을 추적할 수 있는 방법이 필요합니다. 변경 내용은 다음과 같은 두 가지 다른 형식의 메타데이터로 표시됩니다.

  • 동기화된 각 테이블에 대한 삽입, 업데이트 및 삭제를 추적하는 테이블당 메타데이터

  • 각 노드가 다른 노드에서 수신한 변경 내용을 추적하는 범위당 메타데이터

테이블당 메타데이터는 각 기본 테이블에 대한 추적 테이블 하나를 사용하여 추적됩니다. DbSyncProvider에서 동기화되는 각 데이터베이스에는 기본 테이블과 추적 테이블이 있어야 합니다. 추적 테이블의 기본 키는 기본 테이블과 동일하며 추가 열이 필요합니다. 이러한 열은 다음 표에 설명되어 있습니다. 추가 열의 이름은 표에 나와 있는 이름과 동일할 필요가 없지만 순서와 형식은 추적 테이블에 액세스하는 쿼리나 프로시저와 일치해야 합니다. 이러한 프로시저 중 일부가 데이터와 메타데이터를 선택하고 업데이트하는 저장 프로시저 만들기에 포함되어 있습니다.

설명 업데이트 시점…

<기본 테이블의 PK(기본 키)> - 각 PK 열에 대한 열을 포함하십시오.

기본 테이블의 기본 키 열입니다.

행이 기본 테이블에 삽입될 때. 삽입은 로컬 또는 원격 노드에서 발생할 수 있습니다.

update_scope_local_id

마지막으로 업데이트 또는 삭제를 수행한 범위의 ID입니다. 로컬 노드에서 발생한 업데이트나 삭제의 경우에는 이 열이 NULL입니다.

범위 정보 테이블의 scope_local_id 열을 참조하십시오. 자세한 내용은 "범위당 메타데이터에 대한 추적 테이블 만들기"를 참조하십시오.

원격 노드의 업데이트 또는 삭제가 기본 테이블에 적용될 때

scope_update_peer_key

마지막으로 업데이트 또는 삭제를 수행한 노드의 ID입니다.

원격 노드의 업데이트 또는 삭제가 기본 테이블에 적용될 때

scope_update_peer_timestamp

행이 원래 업데이트되거나 삭제되었을 때 원격 데이터베이스의 타임스탬프 값입니다.

원격 노드의 업데이트 또는 삭제가 기본 테이블에 적용될 때

local_update_peer_key

로컬 노드의 ID입니다. 로컬 데이터베이스가 백업에서 복원되지 않은 한 이 열은 각 행에 대해 0 값을 포함합니다. 1

로컬 작업 또는 원격 노드의 업데이트 또는 삭제가 기본 테이블에 적용될 때

local_update_peer_timestamp

로컬 데이터베이스에서 행이 업데이트되거나 삭제되었을 때 로컬 데이터베이스의 타임스탬프 값입니다. 1

로컬 작업 또는 원격 노드의 업데이트 또는 삭제가 기본 테이블에 적용될 때

create_scope_local_id

삽입을 수행한 범위의 ID입니다. 로컬 노드에서 발생한 업데이트나 삭제의 경우에는 이 열이 NULL입니다.

범위 정보 테이블의 scope_local_id 열을 참조하십시오. 자세한 내용은 방법: 공동 작업 동기화를 위한 서버 데이터베이스 프로비전(SQL Server 이외)에서 "범위당 메타데이터에 대한 추적 테이블 만들기"를 참조하십시오.

원격 노드의 삽입이 기본 테이블에 적용될 때

scope_create_peer_key

삽입을 수행한 노드의 ID입니다.

원격 노드의 삽입이 기본 테이블에 적용될 때

scope_create_peer_timestamp

행이 원래 삽입되었을 때 원격 데이터베이스의 타임스탬프 값입니다.

원격 노드의 삽입이 기본 테이블에 적용될 때

local_create_peer_key

로컬 노드의 ID입니다. 로컬 데이터베이스가 백업에서 복원되지 않은 한 이 열은 각 행에 대해 0 값을 포함합니다. 1

로컬 작업 또는 원격 노드의 삽입이 기본 테이블에 적용될 때

local_create_peer_timestamp

로컬 데이터베이스에서 행이 삽입되었을 때 로컬 데이터베이스의 타임스탬프 값입니다. 1

로컬 작업 또는 원격 노드의 삽입이 기본 테이블에 적용될 때

sync_row_is_tombstone

값이 1이면 메타데이터 항목이 기본 테이블의 삭제에 대한 것입니다.

행이 기본 테이블에서 삭제될 때. 삭제는 로컬 또는 원격 노드에서 발생할 수 있습니다.

last_change_datetime

메타데이터 행이 마지막으로 업데이트된 날짜와 시간입니다.

이 추적 테이블의 행이 삽입되거나 업데이트될 때

restore_timestamp

데이터베이스 복원 시점의 local_update_peer_timestamp 값을 저장합니다. 이 값은 로컬 업데이트 타임스탬프 값으로 사용됩니다.

대개 NULL이지만 복원 프로세스를 통해 설정될 수 있습니다. 행이 업데이트될 때마다 NULL로 설정하십시오.

<필터 열> - 범위에 대해 WHERE 절을 필터링하는 데 사용되는 PK가 아닌 각 열에 대한 열을 추가하십시오.

테이블이 하나 이상의 범위에 대해 필터링되는 경우에만 필요합니다. 삽입, 업데이트 및 삭제에 대한 필터링된 열의 값을 저장합니다.

행은 기본 테이블에서 삽입, 업데이트 또는 삭제됩니다. 삭제는 로컬 또는 원격 노드에서 발생할 수 있습니다.

1 겹치는 범위가 동기화될 경우 Sync Framework에서 사용됩니다. 클라이언트 A의 범위 X와 클라이언트 B의 범위 Y를 동기화하는 데이터베이스 업데이트 예제에서 두 범위에 행 Q가 포함되어 있다고 가정합니다.

  1. 행 Q가 클라이언트 A에서 업데이트된 다음 데이터베이스와 동기화됩니다.

  2. 클라이언트 B가 데이터베이스와 동기화되고 행 Q에 대한 업데이트를 받습니다.

    클라이언트 B는 범위 X를 인식하지 못하므로 클라이언트 A의 변경 내용이 데이터베이스에서 발생한 것처럼 나타나야 합니다. 이 작업은 클라이언트 B 또는 행 Q의 update_scope_local_id에 저장된 범위를 동기화하지 않는 다른 클라이언트와 동기화될 때 local_update_peer_key 및 local_update_peer_timestamp 값을 사용하여 수행됩니다.

  3. 행 Q가 데이터베이스에서 업데이트된 다음 클라이언트 A와 동기화됩니다.

    클라이언트 A는 범위 X를 인식하므로 클라이언트 A 또는 범위 X를 동기화하는 다른 클라이언트와 동기화될 때 scope_update_peer_key 및 scope_update_peer_timestamp 값이 사용됩니다.

추적 테이블 및 동기화 메타데이터와 관련된 다른 모든 개체에 대해 별개의 데이터베이스 스키마를 만드는 것이 좋습니다. 이렇게 하면 메타데이터를 기본 테이블의 데이터와 격리하는 데 도움이 됩니다. 성능을 최적화하려면 다음과 같이 각 추적 테이블에 인덱스를 만드십시오.

  • 데이터가 필터링되지 않은 경우 기본 테이블과 같은 기본 키를 사용하고 local_update_peer_timestamp에 클러스터링되지 않은 인덱스를 만듭니다.

  • 데이터가 필터링된 경우 기본 테이블과 같은 기본 키를 사용하고 (local_update_peer_timestamp, <필터 열> 및 <기본 키 열>에 클러스터링되지 않은 인덱스를 만듭니다.)

다음 코드 예제에서는 Sales.Customer 테이블의 변경 내용을 추적하는 Sync 스키마의 테이블을 만들고 이 테이블에 인덱스를 추가합니다.

CREATE TABLE Sync.Customer_Tracking(
    
    CustomerId uniqueidentifier NOT NULL PRIMARY KEY,          
    
    update_scope_local_id int NULL, 
    scope_update_peer_key int,
    scope_update_peer_timestamp bigint,
    local_update_peer_key int,
    local_update_peer_timestamp timestamp,

    create_scope_local_id int NULL,
    scope_create_peer_key int,
    scope_create_peer_timestamp bigint,
    local_create_peer_key int,
    local_create_peer_timestamp bigint,

    sync_row_is_tombstone int, 
    restore_timestamp bigint, 
    last_change_datetime datetime default NULL)

CREATE NONCLUSTERED INDEX NonClustered_Customer_Tracking
ON Sync.Customer_Tracking ([local_update_peer_timestamp])

추적 테이블을 채우고 업데이트할 트리거 만들기

추적 테이블을 만든 후 각 기본 테이블에 INSERT, UPDATE 및 DELETE 트리거를 추가합니다. 사용자 또는 Sync Framework가 기본 테이블에서 행을 삽입, 업데이트 또는 삭제하면 트리거가 실행되고 해당 행에 대한 메타데이터가 변경 내용 추적 테이블에서 삽입 또는 업데이트됩니다. 다른 노드에서 비롯되어 Sync Framework가 기본 테이블에 변경 내용을 적용한 경우 Sync Framework에서 변경 발생 지점을 반영하도록 변경 내용 추적 테이블을 업데이트합니다.

다음 코드 예제에서는 Sales.Customer 테이블이 업데이트되었을 때 Sales.Customer_Tracking 테이블의 변경 내용 추적 메타데이터를 업데이트하는 트리거를 만듭니다. 삽입 및 삭제 트리거에 대한 예제는 데이터베이스 공급자용 설치 스크립트 방법 항목을 참조하십시오.

CREATE TRIGGER Customer_UpdateTrigger ON Sales.Customer FOR UPDATE
AS    
    UPDATE t    
    SET 
        update_scope_local_id = NULL, local_update_peer_key = 0, 
        restore_timestamp = NULL, last_change_datetime = GetDate() 
    FROM Sync.Customer_Tracking t JOIN inserted i ON t.[CustomerId] = i.[CustomerId]        

데이터베이스의 기존 데이터 처리

각 테이블에 대한 변경 내용 추적 메타데이터는 기본 테이블의 트리거를 통해 삽입 및 업데이트됩니다. 따라서 트리거가 추가되기 전에는 기본 테이블에 삽입된 행에 대한 정보가 변경 내용 추적 테이블에 포함되지 않습니다. 데이터베이스의 기존 데이터를 처리하려면 기존 데이터에 대한 메타데이터를 삽입해야 합니다. 그러면 첫 번째 동기화 세션 동안 모든 행이 대상 데이터베이스에 새로운 삽입으로 보내집니다. 다음 코드 예제에서는 기본 테이블에 트리거를 추가한 후 각 기본 테이블에 대해 실행할 명령을 보여 줍니다.

INSERT INTO [tracking table] ([pk columns], create_scope_local_id, local_create_peer_key, local_create_peer_timestamp, update_scope_local_id, local_update_peer_key, restore_timestamp, sync_row_is_tombstone)
SELECT [pk columns], NULL, 0, @@DBTS+1, NULL, 0, NULL, 0 from [base table] baseT left outer join [tracking table] trackingT
On baseT.[pk columns]=trackingT.[pk columns]
where tracking.[pk columns] is null

범위당 메타데이터에 대한 추적 테이블 만들기

범위당 메타데이터는 대개 각 데이터베이스의 다음 두 테이블을 사용하여 추적됩니다.

  • 범위 정보 테이블에는 각 범위에 대한 동기화 정보가 이진 형식으로 저장됩니다. 범위는 동기화할 데이터를 한 단위로 정의하는 논리적인 테이블 그룹입니다.

  • 범위 매핑 테이블은 특정 범위에 속하는 데이터베이스의 테이블을 식별합니다. 하나의 테이블이 여러 범위에 속할 수 있습니다. 매핑 테이블에는 <범위, 테이블> 쌍마다 항목이 하나씩 포함되어야 합니다.

Sync Framework에서는 이러한 정보를 사용하여 동기화 도중 각 데이터베이스로 보낼 변경 내용을 결정합니다. 응용 프로그램에서는 이러한 정보를 직접 사용할 필요가 없습니다. 노드가 세 개인 다음과 같은 양방향 동기화 토폴로지를 가정합니다.

  1. Node1과 Node2의 모든 변경 내용이 동기화됩니다.

  2. Node1과 Node3이 동기화됩니다.

  3. 사용자가 Node2를 업데이트합니다.

  4. Node3과 Node2가 동기화됩니다.

Node3과 Node2가 동기화될 때 Node3이 먼저 Node1과 동기화되었으므로 Node3에는 Node2의 변경 내용이 이미 대부분 들어 있습니다. Sync Framework에서는 동기화 정보를 통해 이를 인식하고 Node2에서 업데이트된 내용만 동기화합니다. 정보에 대한 자세한 내용은 동기화 정보 이해를 참조하십시오.

범위 정보 테이블의 열은 다음 표에 설명되어 있습니다.

설명 업데이트 시점…

scope_id

범위의 식별자로, 대개 GUID입니다.

업데이트되지 않음

scope_local_id

범위의 정수 식별자입니다. IDENTITY 열이어야 합니다.

업데이트되지 않음

scope_name

범위의 이름입니다.

업데이트되지 않음

scope_sync_knowledge

각 범위에 대한 동기화 정보의 이진 표현입니다.

동기화 세션의 대상에 모든 변경 내용이 적용되었을 때

scope_tombstone_cleanup_knowledge

각 범위에 대한 잊어버린 정보의 이진 표현입니다. 잊어버린 정보는 정리된 메타데이터에 사용됩니다.

동기화 세션의 대상에 모든 변경 내용이 적용되었을 때

scope_timestamp

메타데이터 행이 마지막으로 업데이트된 시점의 타임스탬프 값입니다.

이 추적 테이블의 행이 업데이트될 때

scope_cleanup_timestamp

이 범위에 대해 최근 삭제 표식 정리가 수행된 시점의 타임스탬프 값입니다.

겹치는 테이블이 있는 다른 범위에 대해 삭제 표식이 정리될 때

다음 코드 예제에서는 범위 정보 테이블을 만듭니다.

CREATE TABLE Sync.ScopeInfo(       
    scope_local_id int IDENTITY(1,1),
    scope_id uniqueidentifier default NEWID(),
    scope_name nvarchar(100) NOT NULL PRIMARY KEY,
    scope_sync_knowledge varbinary(max) NULL,
    scope_tombstone_cleanup_knowledge varbinary(max) NULL,
    scope_timestamp timestamp,
    scope_cleanup_timestamp bigint)

범위 정보 테이블은 범위 이름을 기반으로 특정 범위에 대한 정보를 검색하기 위해 거의 항상 쿼리됩니다. 따라서 기본 키가 scope_name 열에 정의됩니다.

범위 매핑 테이블의 열은 다음 표에 설명되어 있습니다.

설명 업데이트 시점…

table_name

테이블의 이름입니다.

업데이트되지 않음

scope_name

범위의 이름입니다.

업데이트되지 않음

다음 코드 예제에서는 범위 매핑 테이블을 만들고 이 테이블에 인덱스를 만듭니다.

CREATE TABLE Sync.ScopeTableMap(       
    scope_name nvarchar(100) ,
    table_name nvarchar(100)     
    )

CREATE UNIQUE CLUSTERED INDEX Clustered_ScopeTableMap ON Sync.ScopeTableMap(scope_name, table_name)

동기화할 범위 정의

범위 테이블을 만든 후 동기화할 하나 이상의 범위를 결정합니다. 예를 들어 Sales라는 범위를 정의하고 이 범위에 Customer, CustomerContact, OrderHeaderOrderDetail 테이블을 포함할 수 있습니다. Sales 범위가 동기화될 때 두 노드 간에 테이블 4개에서 변경된 내용이 교환됩니다. 범위를 정의하는 프로세스는 두 부분으로 구성되어 있습니다.

  1. 다음 코드 예제와 같이 범위 정보 테이블 및 범위 매핑 테이블에 항목을 추가합니다.

    INSERT INTO Sync.ScopeInfo(scope_name) VALUES (''Sales'')
    INSERT INTO Sync.ScopeTableMap(scope_name, table_name) VALUES (''Sales'', ''Sales.Customer'')
    INSERT INTO Sync.ScopeTableMap(scope_name, table_name) VALUES (''Sales'', ''Sales.CustomerContact'')
    
  2. DbSyncProvider 개체의 ScopeName 속성에 범위 이름을 지정하고 이 범위에 포함할 각 테이블에 DbSyncAdapter 개체를 추가합니다. 자세한 내용은 방법: 공동 작업 동기화 구성 및 실행(SQL Server 이외)에서 "ScopeName 및 Connection에 대한 응용 프로그램 코드"를 참조하십시오.

중요

일단 범위를 동기화한 후에는 범위를 변경하면 안 됩니다. 범위에 있는 테이블을 변경하거나 이러한 테이블의 절을 필터링하면 데이터 불일치가 발생할 수 있습니다.

필터링되고 겹치는 범위

기본 테이블의 행 하위 집합이 범위에 포함되는 경우에만 범위가 필터링됩니다. 예를 들어 워싱턴 주의 판매 데이터만 포함하는 sales-WA라는 필터링된 범위를 정의할 수 있습니다. 데이터를 필터링하려면 DbSyncAdapter 개체의 SelectIncrementalChangesCommand 속성에 지정하는 쿼리 또는 프로시저에 적절한 데이터를 선택하는 WHERE 절이 있어야 합니다. 쿼리 또는 프로시저에서는 기본 테이블의 필터 열 대신 추적 테이블의 필터 열을 기준으로 변경 내용을 선택해야 합니다.

지원되지 않는 필터링 형식은 다음과 같습니다.

  • 열 필터링: 변경 내용을 선택하고 적용하는 쿼리 또는 프로시저에 모든 열이 포함되어야 합니다.

  • 필터링에 사용되는 열 업데이트: 사용자가 필터링에 사용되는 열의 값을 업데이트하면 행이 한 범위에서 다른 범위로 이동합니다. 행이 현재 속하는 새 범위로 보내지지만 이전 범위에서 행이 삭제되지는 않습니다.

두 범위 간에 공통되는 데이터를 공유할 경우 범위가 겹칩니다. 예를 들어 products 테이블이 sales 범위와 inventory 범위에 포함될 수 있습니다. 범위는 겹치고 필터링될 수 있습니다. 다음 시나리오에서는 필터링과 겹치기가 발생할 수 있는 방법을 보여 줍니다.

  • 시나리오 1:

    • 범위 1은 sales-WA입니다. 이 범위에는 products, orders(필터: state=WA) 및 order_details(필터: state=WA)가 포함되어 있습니다.

    • 범위 2는 sales-OR입니다. 이 범위에는 products, orders(필터: state=OR) 및 order_details(필터: state=OR)가 포함되어 있습니다.

    이 시나리오에서는 전체 products 테이블이 두 범위에서 공유됩니다. ordersorder_details 테이블은 두 범위에 있지만 필터가 겹치지 않으므로 범위에서 이러한 테이블의 행을 공유하지 않습니다.

  • 시나리오 2:

    • 범위 1은 sales-WA입니다. 이 범위에는 products, orders(필터: state=WA) 및 order_details(필터: state=WA)가 포함되어 있습니다.

    • 범위 2는 sales-Northwest입니다. 이 범위에는 products, orders(필터: state=WA OR state=ID) 및 shippers가 포함되어 있습니다.

    이 시나리오에서도 전체 products 테이블이 두 범위에서 공유됩니다. orders 테이블은 두 범위에 있고 필터가 겹칩니다. 두 범위에서 state=WA 필터를 충족하는 행을 공유합니다. shippersorder_details 테이블은 범위 간에 공유되지 않습니다.

범위를 정의하는 방법은 다양하지만 동기화 토폴로지의 데이터베이스 쌍 사이에 동기화되는 모든 데이터는 한 범위에만 속할 수 있다는 원칙은 지켜야 합니다. 위의 시나리오 2를 예로 들면 데이터베이스 A와 데이터베이스 B가 범위 1을 동기화하고 데이터베이스 A와 데이터베이스 C가 범위 2를 동기화할 수 있습니다. 두 범위에 속하는 productsorders 행 때문에 데이터베이스 A와 데이터베이스 B가 범위 2를 동기화할 수 없습니다.

데이터와 메타데이터를 선택하고 업데이트하는 저장 프로시저 만들기

메타데이터 테이블을 만든 후 기본 테이블과 메타데이터 테이블에 대한 변경 내용을 선택하고 적용하는 SQL 쿼리 또는 저장 프로시저(권장)를 만듭니다. 성능 및 보안상의 이유로 저장 프로시저를 사용하는 것이 좋습니다. 이러한 쿼리 또는 프로시저는 다음과 같은 DbSyncAdapter 명령에 지정됩니다. 이러한 명령에 대한 자세한 내용은 방법: 공동 작업 동기화 구성 및 실행(SQL Server 이외)에서 "동기화 어댑터"를 참조하십시오.

다음 코드 예제에서는 Sales.Customer 테이블의 데이터 및 메타데이터 변경 내용을 처리하는 저장 프로시저 집합을 만듭니다. 데이터를 선택하고 업데이트를 처리하는 프로시저만 포함되어 있으며 삽입 및 삭제를 위한 프로시저는 없어서 간결합니다. 삽입 및 삭제 프로시저에 대한 예제는 데이터베이스 공급자용 설치 스크립트 방법 항목을 참조하십시오. 이러한 모든 저장 프로시저를 쉽게 만들 수 있는 템플릿은 서버 제공 템플릿을 참조하십시오.

이 항목의 끝 부분에 나오는 전체 코드 예제를 보면 이러한 프로시저에 전달되는 많은 값을 세션 변수에서 가져온다는 것을 알 수 있습니다. 세션 변수는 Sync Framework에서 동기화 세션 중에 여러 가지 값을 명령에 전달할 수 있게 하는 기본 제공 변수입니다. 세션 변수에 대한 자세한 내용은 방법: 공동 작업 동기화에 세션 변수 사용을 참조하십시오.

SelectIncrementalChangesCommand 프로시저

create procedure Sync.sp_Customer_SelectChanges (
    @sync_min_timestamp bigint,
    @sync_metadata_only int,
    @sync_scope_local_id int,
    @sync_initialize int
)
as

--if @sync_initialize = 0
--begin
    -- Perform additional logic if required.
--end
    
begin
    select  t.CustomerId, 
            c.CustomerName,
            c.SalesPerson,
            c.CustomerType, 
            t.sync_row_is_tombstone,
            t.local_update_peer_timestamp as sync_row_timestamp, 
            case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                 then case when (t.restore_timestamp is null) then t.local_update_peer_timestamp else t.restore_timestamp end else t.scope_update_peer_timestamp end as sync_update_peer_timestamp,
            case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                 then t.local_update_peer_key else t.scope_update_peer_key end as sync_update_peer_key,
            case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                 then t.local_create_peer_timestamp else t.scope_create_peer_timestamp end as sync_create_peer_timestamp,
            case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                 then t.local_create_peer_key else t.scope_create_peer_key end as sync_create_peer_key
    from Sales.Customer c right join Sync.Customer_Tracking t on c.CustomerId = t.CustomerId
    where t.local_update_peer_timestamp > @sync_min_timestamp
end

UpdateCommand 프로시저

CREATE PROCEDURE Sync.sp_Customer_ApplyUpdate (                                    
        @CustomerId uniqueidentifier,
        @CustomerName nvarchar(100),
        @SalesPerson nvarchar(100),
        @CustomerType nvarchar(100),
        @sync_min_timestamp bigint ,                                
        @sync_row_count int OUT,
        @sync_force_write int)        
AS      
    UPDATE c
    SET c.CustomerName = @CustomerName, c.SalesPerson = @SalesPerson, c.CustomerType = @CustomerType      
    FROM Sales.Customer c JOIN Sync.Customer_Tracking t ON c.CustomerId = t.CustomerId
    WHERE ((t.local_update_peer_timestamp <= @sync_min_timestamp) OR @sync_force_write = 1)
        AND t.CustomerId = @CustomerId  
    SET @sync_row_count = @@rowcount

UpdateMetadataCommand 프로시저

create procedure Sync.sp_Customer_UpdateMetadata (
        @CustomerId uniqueidentifier,
        @sync_scope_local_id int,
        @sync_row_is_tombstone int,
        @sync_create_peer_key int,
        @sync_create_peer_timestamp bigint,                 
        @sync_update_peer_key int,
        @sync_update_peer_timestamp timestamp,                      
        @sync_row_timestamp timestamp,
        @sync_check_concurrency int,        
        @sync_row_count int out)        
as  
    declare @was_tombstone int
    select @was_tombstone = sync_row_is_tombstone from Sync.Customer_Tracking 
    where CustomerId = @CustomerId
    
    if (@was_tombstone is not null and @was_tombstone=1 and @sync_row_is_tombstone=0)
        -- tombstone is getting resurrected, update creation version as well
        update Sync.Customer_Tracking set
            [update_scope_local_id] = @sync_scope_local_id, 
            [scope_update_peer_key] = @sync_update_peer_key,
            [scope_update_peer_timestamp] = @sync_update_peer_timestamp,
            [local_update_peer_key] = 0,
            [restore_timestamp] = NULL,
            [create_scope_local_id] = @sync_scope_local_id, 
            [scope_create_peer_key] = @sync_create_peer_key, 
            [scope_create_peer_timestamp] =  @sync_create_peer_timestamp, 
            [sync_row_is_tombstone] = @sync_row_is_tombstone                        
        where CustomerId = @CustomerId          
        and (@sync_check_concurrency = 0 or local_update_peer_timestamp = @sync_row_timestamp)
    else    
        update Sync.Customer_Tracking set
            [update_scope_local_id] = @sync_scope_local_id, 
            [scope_update_peer_key] = @sync_update_peer_key,
            [scope_update_peer_timestamp] = @sync_update_peer_timestamp,
            [local_update_peer_key] = 0,
            [restore_timestamp] = NULL,
            [sync_row_is_tombstone] = @sync_row_is_tombstone                        
        where CustomerId = @CustomerId          
        and (@sync_check_concurrency = 0 or local_update_peer_timestamp = @sync_row_timestamp)
    set @sync_row_count = @@rowcount

SelectRowCommand 프로시저

create procedure Sync.sp_Customer_SelectRow
        @CustomerId uniqueidentifier,
        @sync_scope_local_id int
as
    select  t.CustomerId, 
            c.CustomerName,
            c.SalesPerson,
            c.CustomerType, 
            t.sync_row_is_tombstone,
            t.local_update_peer_timestamp as sync_row_timestamp, 
            case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                 then case when (t.restore_timestamp is null) then t.local_update_peer_timestamp else t.restore_timestamp end else t.scope_update_peer_timestamp end as sync_update_peer_timestamp,
            case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                 then t.local_update_peer_key else t.scope_update_peer_key end as sync_update_peer_key,
            case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                 then t.local_create_peer_timestamp else t.scope_create_peer_timestamp end as sync_create_peer_timestamp,
            case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                 then t.local_create_peer_key else t.scope_create_peer_key end as sync_create_peer_key
    from Sales.Customer c right join Sync.Customer_Tracking t on c.CustomerId = t.CustomerId    
    where c.CustomerId = @CustomerId 

SelectMetadataForCleanupCommand 프로시저

CREATE PROCEDURE Sync.sp_Customer_SelectMetadata     
    @metadata_aging_in_days int,
    @sync_scope_local_id int
AS
    IF @metadata_aging_in_days = -1
        BEGIN
            SELECT  CustomerId,
                    local_update_peer_timestamp as sync_row_timestamp,  
                    case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                        then case when (restore_timestamp is null) then local_update_peer_timestamp else restore_timestamp end else scope_update_peer_timestamp end as sync_update_peer_timestamp,
                    case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                        then local_update_peer_key else scope_update_peer_key end as sync_update_peer_key,
                    case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                        then local_create_peer_timestamp else scope_create_peer_timestamp end as sync_create_peer_timestamp,
                    case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                        then local_create_peer_key else scope_create_peer_key end as sync_create_peer_key
            FROM Sync.Customer_Tracking
            WHERE sync_row_is_tombstone = 1
        END
    
    ELSE
        BEGIN
            SELECT  CustomerId,
                    local_update_peer_timestamp as sync_row_timestamp,  
                    case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                        then case when (restore_timestamp is null) then local_update_peer_timestamp else restore_timestamp end else scope_update_peer_timestamp end as sync_update_peer_timestamp,
                    case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                        then local_update_peer_key else scope_update_peer_key end as sync_update_peer_key,
                    case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                        then local_create_peer_timestamp else scope_create_peer_timestamp end as sync_create_peer_timestamp,
                    case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                        then local_create_peer_key else scope_create_peer_key end as sync_create_peer_key
            FROM Sync.Customer_Tracking
            WHERE sync_row_is_tombstone = 1 AND
            DATEDIFF(day, last_change_datetime, GETDATE()) > @metadata_aging_in_days
        END

결론

이 항목에서는 변경 내용 추적을 위한 데이터베이스 프로비전 과정에 대해 알아보았습니다. 데이터베이스를 프로비전한 후 다른 노드와 동기화할 수 있습니다. 동기화를 구성하고 실행하는 방법에 대한 자세한 내용은 방법: 공동 작업 동기화 구성 및 실행(SQL Server 이외) 항목을 참조하십시오.

참고 항목

개념

다른 ADO.NET 호환 데이터베이스 동기화
방법: 공동 작업 동기화 구성 및 실행(SQL Server 이외)