트랜잭션 처리
트랜잭션 받는 사람
트랜잭션된 수신기와 트랜잭션되지 않은 수신기 간의 기본 차이점은 트랜잭션된 수신기가 명시적 MSDTC 트랜잭션을 만들고 사용하여 데이터 원본과 BizTalk Server MessageBox 데이터베이스 간의 원자성을 보장한다는 것입니다. 일반적으로 어댑터의 다른 모든 측면은 동일합니다.
요청-응답 수신 어댑터는 원래 요청 메시지를 메시징 엔진으로 전송하기 위한 용도로만 트랜잭션을 사용합니다. 메시징 엔진이 어댑터로 보내는 응답을 전송하려면 다른 트랜잭션이 필요합니다. 이는 첫 번째 트랜잭션의 범위가 어댑터와 MessageBox 데이터베이스 간이기 때문입니다. 원래 요청 메시지에 대한 트랜잭션이 커밋되어야만 후속 요청 메시지가 메시징 엔진에서 어댑터로 전송됩니다.
다음 개체 상호 작용 다이어그램은 들어오는 메시지의 트랜잭션 전송 중에 어댑터와 메시징 엔진 간의 상호 작용을 보여 줍니다. 이 예에서 수행되는 상호 작용 순서는 다음과 같습니다.
어댑터가 엔진에서 새 일괄 처리를 받습니다.
어댑터가 MSDTC 트랜잭션을 새로 만듭니다.
어댑터가 트랜잭션에 등록된 데이터 소스에서 삭제 읽기를 수행합니다.
어댑터가 메시지를 전송합니다.
어댑터는 일괄 처리에서 Done 을 호출하여 MSDTC 트랜잭션 및 BatchComplete 콜백 포인터를 전달합니다. 엔진은 IBTDTCCommitConfirm 인터페이스를 반환합니다.
엔진은 일괄 처리를 처리하고, BatchComplete 구현에서 어댑터를 다시 호출하고, 메시지 처리의 상태 어댑터에 전달합니다.
일괄 처리에 성공한 경우 어댑터는 트랜잭션을 커밋하고 커밋을 나타내는 값으로
true
IBTDTCCommitConfirm.DTCCommitConfirm API를 호출합니다.
트랜잭션 전송기
트랜잭션 어댑터는 대체로 비트랜잭션 어댑터와 매우 비슷합니다. 주요 차이점은 트랜잭션 어댑터가 메시지의 데이터를 MSDTC 트랜잭션에 등록된 리소스로 보낸다는 것입니다.
구현 팁: 트랜잭션된 전송의 경우 어댑터는 대상에 데이터를 쓰고 IBTTransportBatch.DeleteMessage 메서드 호출을 통해 데이터를 삭제하는 데 동일한 MSDTC 트랜잭션을 사용해야 합니다. 이 두 개의 작업만 트랜잭션하면 됩니다. IBTTransportBatch.Resubmit, IBTTransportBatch.MoveToNextTransport 및 IBTTransportBatch.MoveToSuspendQ와 같은 다른 작업은 거래할 필요가 없습니다. 이는 엔진이 암시적으로 트랜잭션을 사용하며 이러한 유형의 작업은 대상과 관련해서 원자성을 가질 필요가 없기 때문입니다.
다음 개체 상호 작용 다이어그램은 어댑터와 엔진 간의 상호 작용을 보여 줍니다. 작업이 진행되는 순서는 다음과 같습니다.
엔진이 어댑터에서 새 일괄 처리를 받습니다.
엔진이 새 일괄 처리에 두 개의 메시지를 추가합니다.
엔진은 일괄 처리에서 Done 을 호출하여 어댑터가 스레드 풀에서 서비스되는 내부 전송 큐에 일괄 처리를 게시합니다.
어댑터가 MSDTC 트랜잭션을 새로 만듭니다.
어댑터가 MSDTC 트랜잭션에 대상을 등록하는 메시지를 전송합니다. 예를 들어 SQL Server 데이터베이스에 쓸 수 있습니다.
전송 후 어댑터가 엔진에서 새 일괄 처리를 받습니다.
어댑터는 성공적으로 전송된 메시지에 대해 DeleteMessage 를 호출합니다.
어댑터는 DTC 트랜잭션을 전달하는 일괄 처리에서 Done 을 호출합니다. 엔진은 IBTDTCCommitConfirm 인터페이스를 반환합니다.
엔진이 일괄 처리를 수행하고 응용 프로그램 큐에서 메시지를 삭제합니다.
엔진은 삭제 작업의 성공에 대한 정보를 사용하여 어댑터의 IBTBatchCallback 인터페이스를 다시 호출합니다.
일괄 처리에 성공하면 어댑터가 트랜잭션을 커밋합니다.
어댑터는 IBTDTCCommitConfirm.DTCCommitConfirm 을 호출하여 트랜잭션이 성공적으로 커밋되었음을 엔진에 알릴 수 있습니다.
트랜잭션 간청-응답 어댑터
양방향 수신과 달리 양방향 송신은 동일한 DTC 트랜잭션을 사용하여 수행할 수 있습니다. 트랜잭션된 solicit-response 어댑터는 SubmitResponseMessage 및 DeleteMessage 작업에 동일한 IBTTransportBatch를 사용해야 합니다. 이 일괄 처리는 간청-응답 메시지 쌍을 보내고 받는 데 사용되는 것과 동일한 MSDTC 트랜잭션을 사용해야 합니다. 이렇게 하면 간청-응답 메시지 교환의 원자성이 보장됩니다.
서비스 구성 요소 및 BYOT
메시징 엔진 API를 사용하려면 MSDTC 트랜잭션을 제공해야 합니다. 그러나 일부 .NET 구성 요소는 서비스 구성 요소로 사용되며 프로그래밍 방식의 트랜잭션 커밋이나 중단을 허용하지 않습니다. 대신 해당 플랫폼의 COM+ 런타임에서 자동으로 트랜잭션을 커밋합니다.
이러한 시나리오에서는 어댑터가 BYOT(Bring Your Own Transaction)를 사용해야 합니다. 이렇게 하면 어댑터가 MSDTC 트랜잭션을 만들고, 해당 트랜잭션을 사용하는 .NET 구성 요소를 인스턴스화하고, 해당 구성 요소가 자체 트랜잭션을 만드는 대신 만들어진 트랜잭션을 상속하도록 할 수 있습니다. 이 .NET Framework 이 목적을 위해 System.EnterpriseServices.BYOT를 제공합니다. SDK BaseAdapter는 이 목적을 위해 도우미 클래스 BYOTTransaction을 제공합니다.
경합 상태 방지
트랜잭션 개체를 만들고 BizTalk Server 전달하는 어댑터를 작성하는 경우 다음을 수행하는 코드를 작성해야 합니다.
일괄 처리와 연결된 메시지의 오류를 수정합니다.
일괄 처리 작업과 연결된 트랜잭션의 최종 결과를 결정합니다.
어댑터는 내부 추적 데이터를 유지 관리하기 위해 트랜잭션의 최종 결과에 대해 BizTalk Server 알려야 합니다. 어댑터는 DTCConfirmCommit을 호출하여 결과를 BizTalk Server 알려줍니다. 어댑터가 이 작업을 수행하지 않으면 상당한 메모리 누수가 발생합니다.
위에 나열된 두 작업(오류 해결 및 최종 결과 결정)은 단순해 보이지만 실제로 여러 스레드의 정보를 사용합니다.
어댑터는 어댑터의 BatchComplete 콜백에 BizTalk Server 전달된 정보에 따라 오류를 처리합니다. 이 콜백은 어댑터의 스레드에 있습니다.
DTCConfirmCommit 은 IBTDTCCommitConfirm 개체의 메서드입니다. IBTDTCCommitConfirm 개체의 instance 일괄 처리 IBTTransportBatch::D one 호출에 의해 반환됩니다. 이 instance 어댑터의 스레드와 다른 IBTTransportBatch::D one 호출과 동일한 스레드에 있습니다.
어댑터가 IBTTransportBatch::D를 호출할 때마다 일괄 처리 제출 결과를 보고하기 위해 메시징 엔진이 별도의 스레드에서 호출하는 해당 콜백 BatchComplete가 있습니다. BatchComplete에서 어댑터는 일괄 처리의 통과 또는 실패 여부에 따라 트랜잭션을 커밋하거나 롤백해야 합니다. 두 경우 모두 어댑터는 DTCConfirmCommit을 호출하여 트랜잭션의 상태 메시징 엔진에 보고해야 합니다.
어댑터의 BatchComplete 구현은 BatchComplete가 실행될 때 IBTTransportBatch::D one에서 반환된 IBTDTCCommitConfirm 개체를 항상 사용할 수 있다고 가정할 수 있기 때문에 가능한 경합 조건이 있습니다. 그러나 BatchComplete 는 IBTTransportBatch::D one 이 반환되기 전에 별도의 메시징 엔진 스레드에서 호출할 수 있습니다. 어댑터가 BatchComplete 구현의 일부로 IBTDTCCommitConfirm 개체에 액세스하려고 하면 액세스 위반이 발생할 수 있습니다.
다음 예에서 이 문제는 이벤트를 사용하여 해결됩니다. 여기서는 이벤트를 사용하는 속성을 통해 인터페이스 포인터에 액세스합니다. get은 항상 set을 기다립니다.
protected IBTDTCCommitConfirm CommitConfirm
{
set
{
this.commitConfirm = value;
this.commitConfirmEvent.Set();
}
get
{
this.commitConfirmEvent.WaitOne();
return this.commitConfirm;
}
}
protected IBTDTCCommitConfirm commitConfirm = null;
private ManualResetEvent commitConfirmEvent = new ManualResetEvent(false);
이제 IBTTransportBatch::D one 의 반환 값을 이 속성에 할당하고 BatchComplete 호출에 사용합니다.