Закрытие соединения при использовании Dapper

необходимо ли закрывать соединение после выполнения запроса, явно вызывающего метод Close или помещающего соединение в оператор Using? Приведет ли оставление соединения открытым к повторному использованию соединения и повышению производительности SQL для будущих запросов?

1 ответов


Я предполагаю, что вы используете последнюю версию щеголь.

С Dapper есть два способа управления подключением:

  • полностью управлять собой: Здесь, вы несете полную ответственность за открытие и закрытие соединения. Это так же, как вы относитесь к connection во время работы с ADO.NET.

  • позвольте Dapper управлять им: Dapper автоматически открывает соединение (если его не было открыт) и закрывает его (если он был открыт Dapper) для вас. Это похоже на DataAdapter.Fill() метод. я лично не рекомендую этот способ. это может быть применимо не каждый раз. Далее следует то, что Марк Гравелл говорит в одном из комментарий для этого ответа:https://stackoverflow.com/a/12629170/5779732

ну, технически open / closed отличается от disposed. Если вы только собираетесь открывать / закрывать вокруг отдельных вызовов, вы могли бы также позволить dapper сделать это. если вы открываете / закрываете при более широкой детализации (например, по запросу), было бы лучше, чтобы ваш код сделал это и передал открытое соединение dapper.

конечно, вы можете вызвать несколько запросов на одном соединении. Но, соединение должно быть закрыто (путем вызова Close(), Dispose() метод или путем заключать его в using block), Чтобы избежать утечки ресурсов. Закрытие соединения возвращает его пул соединений. Привлечение пула соединений повышает производительность по сравнению с новой стоимостью соединения.


в дополнение к просто обработке соединения, я предлагаю вам реализовать UnitOfWork для управления транзакциями. См.этой отличный образец на 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);
}

таким образом, вместо того, чтобы непосредственно подвергать соединение в коде вызова, вы управляете им в одном месте.

более подробную информацию о репозитории в приведенном выше коде можно найти здесь.

обратите внимание:UnitOfWork is больше чем просто сделка. Однако этот код обрабатывает только транзакции. Этот код можно расширить, чтобы охватить дополнительные роли.