"사용"블록에서 SqlConnection이 반환 또는 예외로 닫혔습니까?


136

첫 번째 질문 :
내가 가지고 있다고

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();

    string storedProc = "GetData";
    SqlCommand command = new SqlCommand(storedProc, connection);
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

    return (byte[])command.ExecuteScalar();
}

연결이 닫혔습니까? 기술적 }으로 우리는 return이전 과 다름 없이 끝까지 도달하지 않기 때문입니다.

두번째 질문 :
이번에는 :

try
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        int employeeID = findEmployeeID();

        connection.Open();
        SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));
        command.CommandTimeout = 5;

        command.ExecuteNonQuery();
    }
}
catch (Exception) { /*Handle error*/ }

이제 어딘가에 try오류가 발생하면 오류가 발생합니다. 연결이 여전히 닫혀 있습니까? 다시, 우리는 코드의 나머지 코드를 건너 뛰고 명령문 try으로 직접 이동 catch합니다.

using작동 방식에 너무 선형 적으로 생각하고 있습니까? 즉 Dispose(), 우리가 using범위를 벗어날 때 단순히 호출 됩니까 ?

답변:


178
  1. 예.

어느 쪽이든, 사용 블록이 종료되면 (성공적으로 완료되거나 오류로 인해) 닫힙니다.

비록 나중에 지원할 새로운 유지 보수 프로그래머조차도 앞으로 일어날 일을 훨씬 쉽게 알 수 있기 때문에 이렇게 구성하는 것이 더 좋을 것이라고 생각합니다 .

using (SqlConnection connection = new SqlConnection(connectionString)) 
{    
    int employeeID = findEmployeeID();    
    try    
    {
        connection.Open();
        SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));
        command.CommandTimeout = 5;

        command.ExecuteNonQuery();    
    } 
    catch (Exception) 
    { 
        /*Handle error*/ 
    }
}

3
@TrueWill-동의합니다. 방금 구조를 위해 코드를 조금 움직였습니다.
David

10
질문 : Using 문을 사용할 때 연결을 열어야합니까?
Fandango68

3
또한 당신은을함으로써, 트랜잭션을 사용하는 경우 try catch내에서 using명시 적으로 할 수 .Commit또는 .Rollback거래에서 catch. 이것은 더 읽기 쉽고 명시 적이며 예외 유형에 맞는 경우 커밋 할 수 있습니다. conn.Close커밋되지 않은 트랜잭션은 암시 적으로 롤백됩니다 .
Chris

8
@ Fernando68 네, 여전히 Open연결 되어 있어야합니다. using객체의 Dispose메소드가 호출 되도록 보장합니다 .
juharr

블록을 사용하여 ExecuteScalar를 반환했습니다. 그리고 두 번째 방법을 실행하면 연결이 열린 것처럼 매우 빠릅니다. 두 번째로 너무 빠른 이유는 무엇입니까?
긍정적 인 관점

46

두 질문에 모두 그렇습니다. using 문은 try / finally 블록으로 컴파일됩니다.

using (SqlConnection connection = new SqlConnection(connectionString))
{
}

와 같다

SqlConnection connection = null;
try
{
    connection = new SqlConnection(connectionString);
}
finally
{
   if(connection != null)
        ((IDisposable)connection).Dispose();
}

편집 : 일회용 캐스트 캐스트 http://msdn.microsoft.com/en-us/library/yh598w02.aspx


정확하지는 않지만 충분히 가깝습니다. 정확한 차이는 중요하지 않습니다.
Bryan

@Bryan은 그것을 얻지 못했습니다, 당신은 정확한 차이를 언급 할 수 있습니까, 우리가 더 많이 기댈 수 있습니다 :-)
mohits00691

와우, 그것은 오래 전에 작성된 의견이었습니다 :) 그 의견을 작성한 다음날 편집이있는 것처럼 보입니다. 나는 그것이 내가 생각했던 차이라고 생각합니다.
Bryan

@Bryan 네, 귀하의 의견에 따라 조정을 수정했습니다.
Ryan Pedersen

17

여기 내 템플릿이 있습니다. SQL 서버에서 데이터를 선택하는 데 필요한 모든 것. 연결이 닫히고 삭제되고 연결 및 실행 오류가 발생합니다.

string connString = System.Configuration.ConfigurationManager.ConnectionStrings["CompanyServer"].ConnectionString;
string selectStatement = @"
    SELECT TOP 1 Person
    FROM CorporateOffice
    WHERE HeadUpAss = 1 AND Title LIKE 'C-Level%'
    ORDER BY IntelligenceQuotient DESC
";
using (SqlConnection conn = new SqlConnection(connString))
{
    using (SqlCommand comm = new SqlCommand(selectStatement, conn))
    {
        try
        {
            conn.Open();
            using (SqlDataReader dr = comm.ExecuteReader())
            {
                if (dr.HasRows)
                {
                    while (dr.Read())
                    {
                        Console.WriteLine(dr["Person"].ToString());
                    }
                }
                else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
            }
        }
        catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
        if (conn.State == System.Data.ConnectionState.Open) conn.Close();
    }
}

* 개정 : 2015-11-09 *
NickG가 제안한대로; 너무 많은 괄호로 인해 성가신 경우 다음과 같이 포맷하십시오.

using (SqlConnection conn = new SqlConnection(connString))
   using (SqlCommand comm = new SqlCommand(selectStatement, conn))
   {
      try
      {
         conn.Open();
         using (SqlDataReader dr = comm.ExecuteReader())
            if (dr.HasRows)
               while (dr.Read()) Console.WriteLine(dr["Person"].ToString());
            else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
      }
      catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
      if (conn.State == System.Data.ConnectionState.Open) conn.Close();
   }

EA 나 DayBreak 게임을 위해 일한다면 나중에 줄 바꿈을 잊어 버릴 수 있습니다. 내가 맞아? 23이 아닌 1 줄은 내가 더 나은 프로그래머라는 것을 의미합니다.

using (SqlConnection conn = new SqlConnection(connString)) using (SqlCommand comm = new SqlCommand(selectStatement, conn)) { try { conn.Open(); using (SqlDataReader dr = comm.ExecuteReader()) if (dr.HasRows) while (dr.Read()) Console.WriteLine(dr["Person"].ToString()); else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)"); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } if (conn.State == System.Data.ConnectionState.Open) conn.Close(); }

휴 ... 좋아. 나는 그것을 내 시스템에서 꺼내어 잠시 동안 나 자신을 즐겁게 해왔다. 계속하십시오.


6
추가 중괄호없이 명령문을 사용하여 스택 할 수 있다는 것을 알고 있습니까? 마지막 중괄호를 삭제 한 다음 using 문을 서로 옆에 배치하십시오.
NickG

알겠습니다. 감사합니다. 나는 알고 있지만 내 코드가 너무 많은 다른 지름길을 사용하지 않고 무슨 일이 있었는지 정확하게 보여주기를 원했습니다. 그래도 최종 독자에게 추가하는 것이 좋습니다.
ShaneLS

conn.Close();마지막에 왜 사용 합니까? 하지 않습니다 using문은 폐기를 통해 당신을 위해 무엇입니까?
Fredrick Gauss

.net 3.5 이후로 지금은 그렇게 생각합니다. .net 2.0을 사용하여 초기에 분명하지 않았으므로 확인하고 닫는 습관을 들였습니다.
ShaneLS

1
"23이 아닌 1 줄을 의미한다는 것은 내가 더 나은 프로그래머라는 것을 의미합니까?" 나는 당신을 좋아합니다 :-D
Philipp Müller

5

Dispose는 사용 범위를 벗어날 때 간단히 호출됩니다. "사용"의 목적은 개발자가 리소스를 폐기 할 수있는 보장 된 방법을 제공하는 것입니다.

에서 MSDN :

using 문 끝에 도달하거나 예외가 발생하여 명령문이 종료되기 전에 제어가 문 블록을 벗어나면 using 문을 종료 할 수 있습니다.


5

Using할당되는 객체 주위에 try / finally를 생성하고 호출 Dispose()합니다.

try / finally 블록을 수동으로 만들고 호출하는 번거 로움을 덜어줍니다. Dispose()


3

첫 번째 예에서 C # 컴파일러는 실제로 using 문을 다음으로 변환합니다.

SqlConnection connection = new SqlConnection(connectionString));

try
{
    connection.Open();

    string storedProc = "GetData";
    SqlCommand command = new SqlCommand(storedProc, connection);
    command.CommandType = CommandType.StoredProcedure;
    command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

    return (byte[])command.ExecuteScalar();
}
finally
{
    connection.Dispose();
}

마지막으로 함수가 리턴되기 전에 명령문이 항상 호출되므로 연결이 항상 닫히거나 삭제됩니다.

따라서 두 번째 예제에서 코드는 다음과 같이 컴파일됩니다.

try
{
    try
    {
        connection.Open();

        string storedProc = "GetData";
        SqlCommand command = new SqlCommand(storedProc, connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add(new SqlParameter("@EmployeeID", employeeID));

        return (byte[])command.ExecuteScalar();
    }
    finally
    {
        connection.Dispose();
    }
}
catch (Exception)
{
}

finally 문에서 예외가 발생하고 연결이 닫힙니다. 외부 catch 절에서는 예외를 볼 수 없습니다.


1
아주 좋은 예 남자,하지만 마지막 주석에 동의하지 않아야합니다. 사용 블록 내에서 예외가 발생하면 외부 캐치에서 문제없이 잡힐 것입니다. 사실 try / catch 블록 안에 블록을 사용하여 2를 작성하여 테스트했습니다. 놀랍게도 블록을 사용하여 내부 초에서 온 예외 오류 메시지가 표시됩니다.
WhySoSerious

1

try / catch 블록 안에 두 개의 using 작성했는데 ShaneLS example 과 같이 내부 using 문에 예외가있는 경우 예외가 같은 방식으로 잡히는 것을 볼 수 있습니다 .

     try
     {
       using (var con = new SqlConnection(@"Data Source=..."))
       {
         var cad = "INSERT INTO table VALUES (@r1,@r2,@r3)";

         using (var insertCommand = new SqlCommand(cad, con))
         {
           insertCommand.Parameters.AddWithValue("@r1", atxt);
           insertCommand.Parameters.AddWithValue("@r2", btxt);
           insertCommand.Parameters.AddWithValue("@r3", ctxt);
           con.Open();
           insertCommand.ExecuteNonQuery();
         }
       }
     }
     catch (Exception ex)
     {
       MessageBox.Show("Error: " + ex.Message, "UsingTest", MessageBoxButtons.OK, MessageBoxIcon.Error);
     }

이다 상관없이 시도 / 캐치 배치는, 예외가 문제없이 잡힐 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.