TransactionScope를 사용하여 비동기 / 대기


114

나는 통합하기 위해 노력하고있어 async/ await우리의 서비스 버스로. SingleThreadSynchronizationContext이 예제를 기반으로 http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx를 구현했습니다 .

그리고 한 가지를 제외하고는 잘 작동합니다 TransactionScope. 나는 내부의 물건을 기다리고 TransactionScope있으며 TransactionScope.

TransactionScopeasync/를 await사용하여 스레드에 항목을 저장하기 때문에 / 와 잘 어울리지 않는 것 같습니다 ThreadStaticAttribute. 이 예외가 발생합니다.

"TransactionScope가 잘못 중첩되었습니다."

TransactionScope작업을 대기열에 추가하기 전에 데이터 를 저장 하고 실행하기 전에 복원하려고했지만 아무것도 변경되지 않는 것 같습니다. 그리고 TransactionScope코드는 엉망이어서 무슨 일이 일어나고 있는지 이해하기가 정말 어렵습니다.

작동하도록하는 방법이 있습니까? 에 대한 대안이 TransactionScope있습니까?


다음은 TransactionScope 오류 pastebin.com/Eh1dxG4a 를 재현하는 매우 간단한 코드 입니다. 단, 여기서 예외는 Transaction Aborted
Yann

일반 SQL 트랜잭션을 사용할 수 있습니까? 아니면 여러 리소스에 걸쳐 있습니까?
Marc Gravell

여러 리소스에 걸쳐 있습니다
Yann

범위를 비동기 메서드로 전달하거나 작업 단위로 식별되는 일종의 공통 컨텍스트에서 검색하는 방법을 제공해야하는 것 같습니다.
Bertrand Le Roy

SingleThreadSynchronizationContext각 최상위 수준에 대해 자체 스레드가있는 별도의 스레드가 필요 합니다 TransactionScope.
Stephen Cleary 2012

답변:


161

.NET Framework 4.5.1 에는 매개 변수 를 사용하는 새 생성자TransactionScope 집합 이 있습니다 TransactionScopeAsyncFlowOption.

MSDN에 따르면 스레드 연속을 통한 트랜잭션 흐름을 가능하게합니다.

내 이해는 다음과 같은 코드를 작성할 수 있다는 것입니다.

// transaction scope
using (var scope = new TransactionScope(... ,
  TransactionScopeAsyncFlowOption.Enabled))
{
  // connection
  using (var connection = new SqlConnection(_connectionString))
  {
    // open connection asynchronously
    await connection.OpenAsync();

    using (var command = connection.CreateCommand())
    {
      command.CommandText = ...;

      // run command asynchronously
      using (var dataReader = await command.ExecuteReaderAsync())
      {
        while (dataReader.Read())
        {
          ...
        }
      }
    }
  }
  scope.Complete();
}

10

답변에 조금 늦었지만 MVC4에서 동일한 문제가 발생했으며 프로젝트 이동 속성을 마우스 오른쪽 버튼으로 클릭하여 프로젝트를 4.5에서 4.5.1로 업데이트했습니다. 애플리케이션 탭 변경 대상 프레임 워크를 4.5.1로 선택하고 다음과 같이 트랜잭션을 사용합니다.

using (AccountServiceClient client = new AccountServiceClient())
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
}

2
Liam

6

Transaction.DependentClone () 메서드로 만든 DependentTransaction 을 사용할 수 있습니다 .

static void Main(string[] args)
{
  // ...

  for (int i = 0; i < 10; i++)
  {

    var dtx = Transaction.Current.DependentClone(
        DependentCloneOption.BlockCommitUntilComplete);

    tasks[i] = TestStuff(dtx);
  }

  //...
}


static async Task TestStuff(DependentTransaction dtx)
{
    using (var ts = new TransactionScope(dtx))
    {
        // do transactional stuff

        ts.Complete();
    }
    dtx.Complete();
}

DependentTransaction으로 동시성 관리

http://adamprescott.net/2012/10/04/transactionscope-in-multi-threaded-applications/


2
Adam Prescott의 예제 자식 작업은 비동기로 표시되지 않았습니다. "do transactional stuff"를 await Task.Delay(500)이 패턴 과 같은 TransactionScope nested incorrectly것으로 바꾸면 자식 작업이 제대로 완료되기 전에 가장 바깥 쪽 TransactionScope (위의 예에 표시되지 않음)가 범위를 종료하므로 실패 합니다. 교체 awaitTask.Wait()그것은 작동하지만, 당신은의 이점을 잃었습니다 async.
mdisibio 2014

이것은 문제를 해결하는 더 어려운 방법입니다. TransactionScope는 모든 배관을 숨기는 것입니다.
Eniola
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.