SqlDataReader를 수동으로 닫고 폐기해야합니까?


90

여기에서 레거시 코드로 작업하고 있으며 SqlDataReader닫히거나 처리되지 않는 인스턴스가 많이 있습니다. 연결이 끊어졌지만 리더를 수동으로 관리해야하는지 잘 모르겠습니다.

이로 인해 성능이 저하 될 수 있습니까?

답변:


125

다음과 같은 독자를 사용하지 마십시오.

SqlConnection connection = new SqlConnection("connection string");
SqlCommand cmd = new SqlCommand("SELECT * FROM SomeTable", connection);
SqlDataReader reader = cmd.ExecuteReader();
connection.Open();
if (reader != null)
{
      while (reader.Read())
      {
              //do something
      }
}
reader.Close(); // <- too easy to forget
reader.Dispose(); // <- too easy to forget
connection.Close(); // <- too easy to forget

대신 using 문으로 래핑합니다.

using(SqlConnection connection = new SqlConnection("connection string"))
{

    connection.Open();

    using(SqlCommand cmd = new SqlCommand("SELECT * FROM SomeTable", connection))
    {
        using (SqlDataReader reader = cmd.ExecuteReader())
        {
            if (reader != null)
            {
                while (reader.Read())
                {
                    //do something
                }
            }
        } // reader closed and disposed up here

    } // command disposed here

} //connection closed and disposed here

using 문을 사용하면 개체를 올바르게 처리하고 리소스를 확보 할 수 있습니다.

잊어 버린 경우 청소를 가비지 수집기에 맡기고 시간이 걸릴 수 있습니다.


24
두 샘플 모두에서 .Close () 문이 필요하지 않습니다. .Dispose () 호출에 의해 처리됩니다.
Joel Coehoorn

7
아마도 null이 아닌 .HasRows인지 확인하고 싶을 것입니다.
JonH

3
@Andrew ExecuteReader에서 예외가 발생하면 어떻게 null을 반환 할 수 있습니까?
csauve

7
@JohH : 예제의 while (reader.Read ())은 .HasRows와 동일한 작업을 수행하며 독자를 첫 번째 행으로 앞으로 이동하려면 .Read가 필요합니다.
csauve

1
@csauve 당신이 맞아요, null을 반환하지 않았을 것 같습니다. SqlDataReader 변수의 값을보고있는 이유를 잘 모르겠습니다.
Andrew

53

SqlCommand.ExecuteReader ()를 사용하여 인스턴스화 된 SqlDataReader를 삭제 해도 기본 연결이 닫히거나 삭제 되지 않습니다 .

두 가지 일반적인 패턴이 있습니다. 첫 번째로 리더는 연결 범위 내에서 열리고 닫힙니다.

using(SqlConnection connection = ...)
{
    connection.Open();
    ...
    using(SqlCommand command = ...)
    {
        using(SqlDataReader reader = command.ExecuteReader())
        {
            ... do your stuff ...
        } // reader is closed/disposed here
    } // command is closed/disposed here
} // connection is closed/disposed here

데이터 액세스 방법으로 연결을 열고 판독기를 반환하는 것이 편리한 경우가 있습니다. 이 경우 반환 된 판독기가 CommandBehavior.CloseConnection을 사용하여 열리도록하는 것이 중요하므로 판독기를 닫거나 폐기하면 기본 연결이 닫힙니다. 패턴은 다음과 같습니다.

public SqlDataReader ExecuteReader(string commandText)
{
    SqlConnection connection = new SqlConnection(...);
    try
    {
        connection.Open();
        using(SqlCommand command = new SqlCommand(commandText, connection))
        {
            return command.ExecuteReader(CommandBehavior.CloseConnection);
        }
    }
    catch
    {
        // Close connection before rethrowing
        connection.Close();
        throw;
    }
}

호출 코드는 다음과 같이 판독기를 처리해야합니다.

using(SqlDataReader reader = ExecuteReader(...))
{
    ... do your stuff ...
} // reader and connection are closed here.

메서드가 SqlDataReader를 반환하는 두 번째 코드 조각에서는 명령이 삭제되지 않습니다. 괜찮습니까? 명령을 처리하고 (사용 블록으로 묶은 다음) 판독기를 반환해도됩니까?
alwayslearning

@alwayslearning 그것이 내가 가진 시나리오입니다 ... SqlDataReader를 호출자에게 반환 할 때 SqlCommand를 닫거나 폐기 할 수 있습니까?
ganders

1
이것은 나쁘다. 정말로using s 를 사용할 수 없다면 finally {}catch 후 블록 에서 dispose를 호출하십시오 . 이것이 작성되는 방식으로 성공적인 명령은 닫히거나 폐기되지 않습니다.
smdrager

2
@smdrager, 대답을 더 자세히 읽으면 그는 독자를 반환하는 방법에 대해 이야기하고 있습니다. .ExecuteReader (CommandBehavior.CloseConnection); 그런 다음 READER를 폐기하면 연결이 종료됩니다. 따라서 호출 메서드는 결과 판독기를 using 문으로 래핑하기 만하면됩니다. using (var rdr = SqlHelper.GetReader ()) {// ...} finally 블록에서 닫았다면 연결이 닫혀 리더가 읽지 못합니다.
Sinaesthetic

@ganders-이전 게시물로 돌아 가기 : 예, SqlCommand를 처리 할 수 ​​있고 처리해야합니다. 이렇게하려면 예제를 업데이트했습니다.
Joe

11

안전을 위해 모든 SqlDataReader 개체를 using 문으로 래핑 합니다 .


그럴 수 있지. 그러나 using 문이 없으면 실제로 성능에 차이가 있습니까?
Jon Ownbey 2009

using 문은 finally 섹션에 close / dispose 메서드를 사용하여 try..finally ... 블록에 DataReader 코드를 래핑하는 것과 같습니다. 기본적으로 개체가 적절하게 처리된다는 것을 "보장"합니다.
Todd

이것은 내가 제공 한 링크에서 바로 나온 것입니다. "using 문은 개체에 대한 메서드를 호출하는 동안 예외가 발생하더라도 Dispose가 호출되도록합니다."
Kon

5
계속 ... "객체를 try 블록에 넣은 다음 finally 블록에서 Dispose를 호출하여 동일한 결과를 얻을 수 있습니다. 실제로 컴파일러가 using 문을 변환하는 방법입니다."
Kon

5

SQLDataReader를 "using"문으로 감싸십시오. 대부분의 문제를 해결해야합니다.

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