2012-02-15 3 views
12

트랜잭션이 커밋되기 전에 트랜잭션에 할당 된 명령을 처리 할 수 ​​있습니까? 다음 코드를 직접 테스트했는데 제대로 작동 한 것 같습니다. 그러나 이것은 아주 작은 예입니다. 따라서 누군가가 확실하게 알고있는 경우 확인을 찾고 있습니다.SqlCommand.Dispose() before SqlTransaction.Commit()?

internal static void TestTransaction() 
{ 
    try 
    { 
     Program.dbConnection.Open(); 
     using (SqlTransaction transaction = Program.dbConnection.BeginTransaction()) 
     { 
      Boolean doRollback = false; 
      for (int i = 0; i < 10; i++) 
      { 
       using (SqlCommand cmd = new SqlCommand("INSERT INTO [testdb].[dbo].[transactiontest] (testvalcol) VALUES (@index)", Program.dbConnection, transaction)) 
       { 
        cmd.Parameters.AddWithValue("@index", i); 
        try 
        { 
         cmd.ExecuteNonQuery(); 
        } 
        catch (SqlException) 
        { 
         doRollback = true; 
         break; 
        } 
       } 
      } 
      if (doRollback) 
       transaction.Rollback(); 
      else 
       transaction.Commit(); 
     } 
    } 
    finally 
    { 
     Program.dbConnection.Close(); 
    } 
} 
+0

커밋을 수행 사용법() {}을 감싸는 유일한 테스트 방법이기 때문에 Command 객체를 폐기해야합니다. 무슨 말을하는지 사용하지 않고 그것을 시도하고 결과를 볼 수 있지만 트랜잭션이 연결뿐만 아니라 명령에 묶여 있다면 .. 그러면 치명적인 오류가 발생합니다 .. – MethodMan

답변

12

연결, 트랜잭션 및 명령 개체는 데이터베이스에 명령을 보내는 수단 일뿐입니다. 일단 명령이 실행되면 데이터베이스가 그것을받습니다. 나중에 명령 개체를 사용하여 수행 한 작업을 처분하거나 태우거나 달에 쏴 버리면이 사실은 바뀌지 않습니다. (롤백 만 가능).

SqlConnection (SqlTransaction 포함 또는 포함하지 않음)의 범위 내에서 원하는만큼 많은 명령을 생성하고 처리 할 수 ​​있습니다. 그리고 하나의 트랜잭션 내에서 원하는만큼의 트랜잭션을 시작하고 처리 할 수 ​​있습니다. SqlConnection. 이를 증명하려면 다음을 참조하십시오.

using (var conn = new SqlConnection(@"server=(local)\sql2008;database=Junk;Integrated Security=SSPI")) 
{ 
    conn.Open(); 
    // Repeat this block as often as you like... 
    using (var tran = conn.BeginTransaction()) 
    { 
    using (var cmd = new SqlCommand("INSERT INTO Mess VALUES ('mess1')", conn, tran)) 
    { 
     cmd.ExecuteNonQuery(); // Shows in Sql profiler 
    } 
    tran.Commit(); // Commits 
    } 
    using (var cmd = new SqlCommand("INSERT INTO Mess VALUES ('mess2')", conn)) 
    { 
    cmd.ExecuteNonQuery(); // Executes and commits (implicit transaction). 
    } 
} 

물론 건강한 코드의 경우 모든 개체를 올바른 순서로 처분해야합니다. SqlConnection을 삭제 한 후 명령을 삭제하면 연결 개체가 메모리에 남아있을 수 있습니다.

+0

왜 잘못된 순서로 처리해야 하는가? 기억에 남을 연결? 나는 그것이 적어도 마지막 명령이나 거래가 처리 될 때까지 머무를 것으로 기대한다. – eFloh

+0

@eFloh 연결 풀의 기본 연결에 대한 참조를 유지하기 때문에. 명령에 아직 명령이 없기 때문에 해당 참조를 잘라낼 수 없습니다. –

+0

오케이, 우리는 같은 뜻입니다. 는 모든 명령이 처리 될 때 심지어 연결이 끝난 후에 처리되는 경우에도 처리됩니다. 나는 처음에 당신의 텍스트가이 경우 결코 처신되지 않을 것이라는 것을 의미하는 것을 이해했습니다 ... – eFloh

1

네, 아마도 안전 할 것입니다. using()은 Connection이 아닌 Command를 닫고 있습니다.

하지만 그 연결을 다른 using() 블록이나 try/finally 구조에 넣어야합니다.

1

확인해 주시면 매우 잘 작동하며 (여기서는 회사에서) 올바른 방법으로 간주됩니다.

  1. 연결을 생성
  2. 생성 트랜잭션
  3. 트랜잭션을 사용하여, 명령 (들)을 생성
  4. 폐기 명령은
  5. 트랜잭션을
  6. 폐기 연결