programing

트랜잭션 범위가 너무 일찍 완료됨

goodsources 2023. 6. 25. 18:45
반응형

트랜잭션 범위가 너무 일찍 완료됨

트랜잭션 범위 내에서 실행되는 코드 블록을 가지고 있으며 이 코드 블록 내에서 DB에 여러 번 호출합니다.전체 범위를 선택, 업데이트, 생성 및 삭제합니다.삭제를 실행할 때 이 쿼리가 잠재적으로 교착 상태에 빠질 수 있으므로 쿼리가 교착 상태가 되면 자동으로 다시 제출되는 SqlCommand의 확장 메서드를 사용하여 삭제를 실행합니다.

교착 상태가 발생하여 함수가 쿼리를 다시 제출하려고 할 때 문제가 발생한다고 생각합니다.다음과 같은 오류가 표시됩니다.

현재 연결과 관련된 트랜잭션이 완료되었지만 삭제되지 않았습니다.SQL 문을 실행하는 데 연결을 사용하려면 먼저 트랜잭션을 삭제해야 합니다.

쿼리를 실행하는 간단한 코드입니다(아래의 모든 코드는 트랜잭션 범위를 사용하여 실행됨).

using (sqlCommand.Connection = new SqlConnection(ConnectionStrings.App))
{
    sqlCommand.Connection.Open();
    sqlCommand.ExecuteNonQueryWithDeadlockHandling();
}

교착 상태 쿼리를 다시 제출하는 확장 메서드는 다음과 같습니다.

public static class SqlCommandExtender
{
    private const int DEADLOCK_ERROR = 1205;
    private const int MAXIMUM_DEADLOCK_RETRIES = 5;
    private const int SLEEP_INCREMENT = 100;

    public static void ExecuteNonQueryWithDeadlockHandling(this SqlCommand sqlCommand)
    {
        int count = 0;
        SqlException deadlockException = null;

        do
        {
            if (count > 0) Thread.Sleep(count * SLEEP_INCREMENT);
            deadlockException = ExecuteNonQuery(sqlCommand);
            count++;
        }
        while (deadlockException != null && count < MAXIMUM_DEADLOCK_RETRIES);

        if (deadlockException != null) throw deadlockException;
    }

    private static SqlException ExecuteNonQuery(SqlCommand sqlCommand)
    {
        try
        {
            sqlCommand.ExecuteNonQuery();
        }
        catch (SqlException exception)
        {
            if (exception.Number == DEADLOCK_ERROR) return exception;
            throw;
        }

        return null;
    }
}

라인에서 오류가 발생합니다.

sqlCommand.ExecuteNonQuery();

트랜잭션 범위에서 선택한 문을 누르는 것을 잊지 마십시오.SQL Server 2005 이상에서는 (nolock)과 함께 사용하는 경우에도 선택한 테이블에 잠금이 계속 생성됩니다.여기에서 트랜잭션 범위를 설정하고 사용하는 방법을 보여줍니다.

using(TransactionScope ts = new TransactionScope 
{ 
  // db calls here are in the transaction 
  using(TransactionScope tsSuppressed = new TransactionScope (TransactionScopeOption.Suppress)) 
  { 
    // all db calls here are now not in the transaction 
  } 
} 

이 메시지는 트랜잭션이 다음 기간보다 더 오래 실행될 때 발생할 수 있습니다.maxTimeout위해서System.Transactions그것은 중요하지 않습니다.TransactionOptions.Timeout증가했습니다. 초과할 수 없습니다.maxTimeout.

기본값:maxTimeout는 10분으로 설정되며 해당 값은 에서만 수정할 수 있습니다.machine.config

구성 수준에서 다음을 추가합니다.machine.config시간 초과를 수정하려면:

<configuration>
    <system.transactions>
        <machineSettings maxTimeout="00:30:00" />
    </system.transactions>
</configuration>

machine.config는 다음 위치에서 찾을 수 있습니다.%windir%\Microsoft.NET\Framework\[version]\config\machine.config

당신은 이 블로그 게시물에서 그것에 대한 더 많은 것을 참조하십시오.

문제를 재현할 수 있습니다.트랜잭션 시간 초과입니다.

using (new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 0, 0, 1)))
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        using (var sqlCommand = connection.CreateCommand())
        {
            for (int i = 0; i < 10000; i++)
            {
                sqlCommand.CommandText = "select * from actor";
                using (var sqlDataReader = sqlCommand.ExecuteReader())
                {
                    while (sqlDataReader.Read())
                    {
                    }
                }
            }
        }
    }
}

던지기System.InvalidOperationException다음 메시지와 함께:

현재 연결과 관련된 트랜잭션이 완료되었지만 삭제되지 않았습니다.SQL 문을 실행하는 데 연결을 사용하려면 먼저 트랜잭션을 삭제해야 합니다.

이 문제를 해결하려면 쿼리를 더 빨리 실행하거나 시간 초과를 늘립니다.

에서 경발우는생하예 안에서 하면,TransactionScope롤니다됩백즉.,즉,TransactionScope완료되었습니다.은 이제 전합다니야금지에 전화해야 .dispose()새 거래를 시작합니다.저는 솔직히 당신이 오래된 것을 재사용할 수 있을지 모르겠습니다.TransactionScope시도해 본 적은 없지만, 안 해본 것 같아요.

제 문제는 바보 같은 문제였습니다. 시간 초과로 디버그 브레이크를 밟으면 이것을 얻을 수 있습니다.얼굴 손바닥

프로그래밍을 하면 가끔은 기분이 좋아져요

트랜잭션 시간 초과로 인해 이 오류가 발생할 수 있음을 확인했습니다.Marcus + Rolf가 언급한 것에 추가하자면, 만약 당신이 명시적으로 시간 제한을 설정하지 않았다면.TransactionScopetimeout TimeSpan은 기본값을 가정합니다.이 기본값은 다음 중 작은 값입니다.

  1. 로을무경우한을 app.config/web.config 예:

    <system.transactions>
    <defaultSettings timeout="00:05:00" />
    </system.transactions>
    
  2. 하만이캡다 '됩지에니 '다것'에서 '.machine.config 팅세<machineSettings maxTimeout="00:10:00" />

이 예외는 사용 안 함으로 인해 발생할 수도 있습니다. Microsoft Distributed Transaction Coordinator.

활성화하려면 "dcomcnfg"를 실행하고 다음을 선택합니다."Component Services" -> "My Computer" -> "Distributed Transaction Coordinator" -> "Local Service DTC""속성"을 선택합니다.

"원격 클라이언트 허용", "인바운드 허용", "아웃바운드 허용" 및 "인증 필요 없음"을 선택해야 합니다.

언급URL : https://stackoverflow.com/questions/2921920/transactionscope-prematurely-completed

반응형