c# - SQL 服务器 : is there any performance penalty for wrapping a SELECT query in a transaction?

标签 c# sql-server ado.net unit-of-work sqltransaction

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

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

除了事务处理之外,我几乎什么都弄明白了。

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

在这方面,这是我在我一直在阅读的一本 SQL 书籍中找到的内容:

Executing a SELECT statement within a transaction can create locks on the referenced tables, which can in turn block other users or sessions from performing work or reading data

这是 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)中你没有手动管理事务,问题是,如果按原样使用此类,即始终创建事务,我是否会造成某种瓶颈?

最佳答案

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

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

关于c# - SQL 服务器 : is there any performance penalty for wrapping a SELECT query in a transaction?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40197865/

相关文章:

c# - 如何从数据库中获取一个简单的字符串

c# - SqlCommand返回值参数

c# - ASP.NET Rotativa 从另一个 Controller 的 View 生成 PDF

c# - 需要有关 Fluent Nhibernate 自动映射的 'No persister for:' 异常的帮助

C# 多类事件

node.js - 根据 API 请求失去与 SQL Server 和 Node 的连接

sql - 什么时候把表分成多个数据库?

mysql - 将mysql插入语句转换为sql server插入语句?

c# - 是否可以在 ASP.Net 属性中设置必需的属性?

asp.net - Entity Framework v2 不支持 sql 2000?