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

edd*_*ddy 1 c# sql-server ado.net unit-of-work sqltransaction

作为学习练习,在尝试使用任何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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我想在我的存储库中使用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;
}
Run Code Online (Sandbox Code Playgroud)

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

Rem*_*anu 6

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

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