SQL Server:在事务中包装SELECT查询是否有任何性能损失?

作为学习练习,在尝试使用任何ORM(如EF)之前,我想使用ADO.NET和存储过程构建个人项目。

因为我不希望我的代码随着时间的推移变得混乱,我想使用一些模式,如存储库和UoW模式。

除了交易处理之外,几乎所有事情都已经解决了。

以某种方式’模拟’一个UoW,我使用了@jgauffin提供的这个类 ,但阻止我使用该类的是每次你创建该类的新实例( AdoNetUnitOfWork )时,你自动开始一个事务并且有一个很多情况下你只需要读取数据。

在这方面,这是我在我读过的一本SQL书中找到的:

在事务中执行SELECT语句可以在引用的表上创建锁定,这可以阻止其他用户或会话执行工作或读取数据

这是AdoNetUnitOfWork类:

 public class AdoNetUnitOfWork : IUnitOfWork { public AdoNetUnitOfWork(IDbConnection connection, bool ownsConnection) { _connection = connection; _ownsConnection=ownsConnection; _transaction = connection.BeginTransaction(); } public IDbCommand CreateCommand() { var command = _connection.CreateCommand(); command.Transaction = _transaction; return command; } public void SaveChanges() { if (_transaction == null) throw new InvalidOperationException("Transaction have already been commited. Check your transaction handling."); _transaction.Commit(); _transaction = null; } public void Dispose() { if (_transaction != null) { _transaction.Rollback(); _transaction = null; } if (_connection != null && _ownsConnection) { _connection.Close(); _connection = null; } } } 

这就是我想在我的存储库中使用UoW的方式:

 public DomainTable Get(int id) { DomainTable table; using (var commandTable = _unitOfWork.CreateCommand()) { commandTable.CommandType = CommandType.StoredProcedure; //This stored procedure contains just a simple SELECT statement commandTable.CommandText = "up_DomainTable_GetById"; commandTable.Parameters.Add(commandTable.CreateParameter("@pId", id)); table = ToList(commandTable).FirstOrDefault(); } return table; } 

我知道我可以稍微调整一下这个代码,以便事务是可选的,但是因为我试图使这个代码尽可能地与平台无关,而且据我所知,在EF等其他持久性框架中你不必管理事务手动,问题是,我是否会通过使用这个类来创建某种瓶颈,也就是说,总是创建事务?

这一切都取决于事务隔离级别 。 使用默认隔离级别(即读取已提交),如果包含在事务中,则SELECT应该不会出现性能损失。 如果一个事务尚未启动,SQL Server会在内部包装事务中的语句,因此您的代码应该几乎完全相同。

但是,我必须问你为什么不使用内置的.Net TransactionScope ? 这样,您的代码将与其他库和框架更好地交互,因为TransactionScope是普遍使用的。 如果你决定切换到这个,我必须警告你,默认情况下, TransactionScope使用SERIALIZABLE隔离级别,这确实会导致性能损失,请参阅使用新的TransactionScope()Considered Harmful 。