2016-11-27 368 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:同意。我纠正了我的答案。我只是说这可能不适用于每一次。 –