2016-11-27 107 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來管理事務。請參閱this GitHub上的優秀示例。

以下源代碼可能對您有所幫助。請注意,這是爲我的需要而編寫的;所以它可能不適合你。

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。我用構造函數選擇依賴注入。

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); 
} 

這種方式,而不是直接暴露在你的呼叫連接代碼,你可以在一個位置控制它。

有關上述代碼中有關Repository的更多詳細信息,請參閱here

請注意,UnitOfWorkmore而不僅僅是交易。儘管這個代碼只處理事務。您可以擴展此代碼以涵蓋其他角色。

+0

我不能完全同意你對你的第二意見。有時讓精巧的管理連接是一個更好的選擇。我想引用來自https://stackoverflow.com/a/12629170/1262198: 的Marc Gravell「技術上的開放/關閉與處置不同,如果您只打算打開/關閉個別通話,您可能會如果你以更大的粒度打開/關閉(比如每個請求),最好讓你的代碼做到這一點,並將打開的連接傳遞給Dapper。「 – Arvand

+0

@Arvand:同意。我糾正了我的答案。我只是說這可能不適用於每一次。 –