2016-11-27 2 views
4

Close 메서드를 명시 적으로 호출하거나 Using 문에 연결을 넣으면 쿼리를 닫아야합니까? 연결을 열어두면 연결 재사용이 가능하고 이후의 쿼리에서 SQL 성능이 향상됩니까?Dapper를 사용할 때 연결 닫기

답변

11

Dapper의 최신 버전을 사용하고 있다고 가정합니다.

  • 완전 직접 관리 :

    이 말끔으로 연결을 관리하는 방법은 두 가지가 여기 , 당신은 개폐 연결을위한 완전히 책임이 있습니다. 이는 ADO.NET으로 작업하는 동안 연결을 처리하는 것과 같습니다.

  • 단정 그것을 관리 할 수 ​​있도록 허용 : 단정 자동으로 (이 개설되지 않은 경우) 연결을 열고 (이 말끔 열 경우) 당신을 위해 그것을 닫습니다. 이것은 DataAdapter.Fill() 메소드와 유사합니다. 개인적으로이 방법을 권장하지 않습니다. 이것은 매번 적용되지 않을 수도 있습니다. 다음은 마크 Gravell이 응답에 대한 comment 중 하나에 말씀입니다 : https://stackoverflow.com/a/12629170/5779732

아니라, 폐쇄/기술적 오픈 배치 다릅니다. 개개인의 전화를 열거 나 닫을 예정이라면, 더할 나위없이 할 수 있습니다. 넓은 입도 (예 : 요청 당)로 열거 나 닫는 경우, 코드가이를 수행하고 dapper에 열린 연결을 전달하는 것이 좋습니다.

물론, 단일 연결에서 여러 쿼리를 호출 할 수 있습니다. 그러나 리소스 누출을 방지하려면 Close(), Dispose() 메서드를 호출하거나 using 블록에 포함하여 연결을 닫아야합니다. 연결을 닫으면 연결 풀로 반환됩니다. 연결 풀이 포함되면 새로운 연결 비용보다 성능이 향상됩니다.


연결을 처리하는 것 외에도 트랜잭션을 관리하기 위해 UnitOfWork를 구현하는 것이 좋습니다. GitHub의 우수 샘플 this을 참조하십시오.

다음 소스 코드가 도움이됩니다. 이것은 내 필요를 위해 작성된 것입니다. 그래서 그것은 당신을 위해 일하지 않을 수도 있습니다.

public sealed class DalSession : IDisposable 
{ 
    public DalSession() 
    { 
     _connection = new OleDbConnection(DalCommon.ConnectionString); 
     _connection.Open(); 
     _unitOfWork = new UnitOfWork(_connection); 
    } 

    IDbConnection _connection = null; 
    UnitOfWork _unitOfWork = null; 

    public UnitOfWork UnitOfWork 
    { 
     get { return _unitOfWork; } 
    } 

    public void Dispose() 
    { 
     _unitOfWork.Dispose(); 
     _connection.Dispose(); 
    } 
} 

public sealed class UnitOfWork : IUnitOfWork 
{ 
    internal UnitOfWork(IDbConnection connection) 
    { 
     _id = Guid.NewGuid(); 
     _connection = connection; 
    } 

    IDbConnection _connection = null; 
    IDbTransaction _transaction = null; 
    Guid _id = Guid.Empty; 

    IDbConnection IUnitOfWork.Connection 
    { 
     get { return _connection; } 
    } 
    IDbTransaction IUnitOfWork.Transaction 
    { 
     get { return _transaction; } 
    } 
    Guid IUnitOfWork.Id 
    { 
     get { return _id; } 
    } 

    public void Begin() 
    { 
     _transaction = _connection.BeginTransaction(); 
    } 

    public void Commit() 
    { 
     _transaction.Commit(); 
     Dispose(); 
    } 

    public void Rollback() 
    { 
     _transaction.Rollback(); 
     Dispose(); 
    } 

    public void Dispose() 
    { 
     if(_transaction != null) 
      _transaction.Dispose(); 
     _transaction = null; 
    } 
} 

interface IUnitOfWork : IDisposable 
{ 
    Guid Id { get; } 
    IDbConnection Connection { get; } 
    IDbTransaction Transaction { get; } 
    void Begin(); 
    void Commit(); 
    void Rollback(); 
} 

이제 리포지토리는이 UnitOfWork를 어떤 방식 으로든 받아 들여야합니다. 저는 Constructor로 Dependency Injection을 선택합니다.

public sealed class MyRepository 
{ 
    public MyRepository(IUnitOfWork unitOfWork) 
    { 
     this.unitOfWork = unitOfWork; 
    } 

    IUnitOfWork unitOfWork = null; 

    //You also need to handle other parameters like 'sql', 'param' ect. This is out of scope of this answer. 
    public MyPoco Get() 
    { 
     return unitOfWork.Connection.Query(sql, param, unitOfWork.Transaction, .......); 
    } 

    public void Insert(MyPoco poco) 
    { 
     return unitOfWork.Connection.Execute(sql, param, unitOfWork.Transaction, .........); 
    } 
} 

그리고는 당신은 다음과 같이 호출 : 트랜잭션과

:

using(DalSession dalSession = new DalSession()) 
{ 
    UnitOfWork unitOfWork = dalSession.UnitOfWork; 
    unitOfWork.Begin(); 
    try 
    { 
     //Your database code here 
     MyRepository myRepository = new MyRepository(unitOfWork); 
     myRepository.Insert(myPoco); 
     //You may create other repositories in similar way in same scope of UoW. 

     unitOfWork.Commit(); 
    } 
    catch 
    { 
     unitOfWork.Rollback(); 
     throw; 
    } 
} 

거래하지 않고 :

using(DalSession dalSession = new DalSession()) 
{ 
    //Your database code here 
    MyRepository myRepository = new MyRepository(dalSession.UnitOfWork);//UoW have no effect here as Begin() is not called. 
    myRepository.Insert(myPoco); 
} 

이 방법 대신 직접 전화의 연결을 노출시키는 코드를 사용하면 한 위치에서 제어 할 수 있습니다.

위 코드의 저장소에 대한 자세한 내용은 here을 참조하십시오.

UnitOfWork은 트랜잭션보다 more입니다. 이 코드는 트랜잭션 만 처리합니다. 추가 역할을 포함하도록이 코드를 확장 할 수 있습니다.

+0

두 번째 의견에 대해서는 완전히 동의 할 수 없습니다. 때로는 연결을 관리하기 위해 dapper를 사용하는 것이 더 나은 선택입니다. https://stackoverflow.com/a/12629170/1262198에서 Marc Gravell의 말을 인용하고 싶습니다. "기술적으로 열린 상태/닫히는 상태와 폐기 상태가 다릅니다. 개별 통화를 시작하거나 닫을 경우에만 만약 당신이 (예를 들어 요청 당 더 넓은 범위로) 열거 나 닫는다면, 당신의 코드가 그것을 수행하고 dapper에 열린 연결을 전달하는 것이 더 좋을 것입니다. " – Arvand

+0

@Arvand : 동의하십시오. 내 대답을 바로 잡았어. 나는 이것이 매번 적용될 수 없다는 것을 의미합니다. –