Закрытие соединения при использовании 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 больше чем просто сделка. Однако этот код обрабатывает только транзакции. Этот код можно расширить, чтобы охватить дополнительные роли.