.net 使用Dapper时关闭连接

dphi5xsq  于 2023-05-23  发布在  .NET
关注(0)|答案(1)|浏览(264)

一旦查询被显式执行,调用Close方法或将连接放在Using语句中,是否有必要关闭连接?让连接保持打开状态是否会导致连接重用并提高SQL在未来查询中的性能?

dxxyhpgq

dxxyhpgq1#

我假设你使用的是最新版本的Dapper。
使用Dapper,有两种方式来管理连接:

***完全管理自己:**在这里,您完全负责打开和关闭连接。这就像您在使用ADO.NET时对待连接的方式一样。
***允许Dapper管理它:**Dapper会自动为您打开连接(如果连接未打开),并关闭连接(如果连接已被Dapper打开)。这类似于DataAdapter.Fill()方法。我个人不推荐这种方式。这可能不是每次都适用。以下是Marc Gravell在评论中对这个答案的评论:https://stackoverflow.com/a/12629170/5779732

技术上来说开/关和处理是不同的。如果你只打算打开/关闭周围的个别电话,你不妨让dapper来做。如果你是在更宽的粒度上打开/关闭(例如,每个请求),那么你的代码最好这样做,并将打开的连接传递给dapper。
下面是这里的报价:
如果需要打开连接,Dapper将关闭连接。所以,如果你只是做一个快速查询-让Dapper处理它。如果你做了很多次,你应该打开(一次),然后在最后关闭,所有的查询都在中间......只是从效率的Angular 来看。
当然,你可以在一个连接上调用多个查询。但是,应该关闭连接(通过调用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。我选择依赖注入与构造函数。

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而不仅仅是一个交易。不过,这段代码只处理事务。您可以扩展此代码以涵盖其他角色。

相关问题