【问题标题】:Is it possible to select data while a transaction is occuring?是否可以在事务发生时选择数据?
【发布时间】:2009-12-17 00:47:54
【问题描述】:

我正在使用 transactionscope 来确保将数据正确读取到数据库中。但是,我可能需要在事务运行时选择一些数据(从另一个页面)。有可能做到这一点吗?我对数据库非常陌生。

我正在使用 LinqToSQL 和 SQL Server 2005(dev)/2008(prod)。

【问题讨论】:

  • 一如既往,最好的答案是:你试过了吗?
  • @delfuego:我不同意,因为有很多事情可能会出错。这种问题应该通过阅读或提问来回答,而不是通过尝试来回答。但是,我建议 OP 阅读一本或几本关于数据库的书籍。

标签: sql-server linq-to-sql transactions


【解决方案1】:

是的,在事务运行时仍然可以从数据库中选择数据。

不受事务影响的数据(例如,表中未更新的行)通常可以从其他事务中读取。 (在某些情况下,SQL Server 会引入一个表锁来停止对表中所有行的读取,但它们是不寻常的,并且通常是您的查询或服务器上发生其他事情的症状)。

您需要查看Transaction Isolation Levels,因为这些确切地控制了此行为的工作方式。

这是设置事务范围的隔离级别的 C# 代码。

TransactionOptions option = new TransactionOptions();        
options.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;        
using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required, options)
{
    // Code within transaction
}

通常,根据在事务上指定的事务隔离级别(或任何表提示,如 NOLOCK),您会获得不同级别的数据锁定,以保护应用程序的其余部分免受与事务相关的活动的影响。例如,使用READUNCOMMITTED 的事务隔离级别,您可以看到该事务中发生的写入。这允许脏读,但也防止(大多数)数据锁定。

规模的另一端是像SERIALIZABLE 这样的隔离级别,可确保您的事务活动在提交之前完全隔离。

【讨论】:

    【解决方案2】:

    除了已经提供的建议之外,我强烈建议您研究快照隔离模型。 Using Snapshot Isolation 有很好的讨论。在数据库上启用 Read Committed Snapshot ON 可以缓解很多争用问题,因为读取器不再被写入器阻塞。由于默认读取是在读取提交隔离模式下执行的,因此这个简单的数据库选项切换具有立竿见影的好处,并且不需要在应用程序中进行任何更改。

    没有免费的午餐,所以这是有代价的,在这种情况下,价格是 tempdb 上的额外负载,请参阅Row Versioning Resource Usage

    如果您使用显式隔离级别,特别是如果您使用默认的 TransactionScope Serializable 模式,那么您将必须检查您的代码以强制执行更有效的 ReadCommited 隔离级别。如果你不知道你使用什么隔离级别,那就意味着你使用了 ReadCommited。

    【讨论】:

      【解决方案3】:

      是的,默认情况下TransactionScope 将锁定事务中涉及的表。如果您需要在事务发生时读取,请输入另一个 TransactionScopeTransactionOptions IsolationLevel.ReadUncommitted

      TransactionScopeOptions = new TransactionScopeOptions();
      options.IsolationLevel = IsolationLevel.ReadUncommitted;
      using(var scope = new TransactionScope(
          TransactionScopeOption.RequiresNew, 
          options
      ) {
          // read the database
      }
      

      使用 LINQ-to-SQL DataContext:

      // db is DataContext
      db.Transaction = 
          db.Connection.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
      

      请注意System.Transactions.IsolationLevelSystem.Data.IsolationLevel 之间存在差异。是的,你没看错。

      【讨论】:

      • 好的,由于不准确,第一次投反对票是公平的,但投反对票的人很友好地发表了评论。 @Second downvoter:怎么了?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-16
      • 1970-01-01
      • 1970-01-01
      • 2016-10-19
      • 1970-01-01
      相关资源
      最近更新 更多