首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TransactionScope和隔离级别

TransactionScope和隔离级别
EN

Stack Overflow用户
提问于 2009-04-06 17:58:19
回答 2查看 19.9K关注 0票数 14

我们在使用TransactionScope时遇到了问题。TransactionScope为我们提供了在数据访问层中使用事务的非常好的灵活性。通过这种方式,我们可以使用隐式或显式事务。ADO.NET事务也有一些性能提升,但目前这还不是真正的问题。然而,我们在锁定方面遇到了问题。在下面的示例代码中,尽管隔离级别设置为ReadCommitted,但在提交主事务(在main方法中)之前,不可能从其他客户端对表testTable执行Select SQL语句,因为整个表上都有锁。我们还尝试在所有方法中只使用一个连接,但行为是相同的。我们的数据库管理系统是SQL Server 2008。是不是有什么我们不明白的?

向Anton Kalcik致敬

请参阅此示例代码:

代码语言:javascript
复制
class Program
{
    public class DAL
    {
        private const string _connectionString = @"Data Source=localhost\fsdf;Initial Catalog=fasdfsa;Integrated Security=SSPI;";

        private const string inserttStr = @"INSERT INTO dbo.testTable (test) VALUES(@test);";

        /// <summary>
        /// Execute command on DBMS.
        /// </summary>
        /// <param name="command">Command to execute.</param>
        private void ExecuteNonQuery(IDbCommand command)
        {
            if (command == null)
                throw new ArgumentNullException("Parameter 'command' can't be null!");

            using (IDbConnection connection = new SqlConnection(_connectionString))
            {
                command.Connection = connection;
                connection.Open();
                command.ExecuteNonQuery();
            }
        }

        public void FirstMethod()
        {
            IDbCommand command = new SqlCommand(inserttStr);
            command.Parameters.Add(new SqlParameter("@test", "Hello1"));

            using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required))
            {
                ExecuteNonQuery(command);
                sc.Complete();
            }
        }

        public void SecondMethod()
        {
            IDbCommand command = new SqlCommand(inserttStr);
            command.Parameters.Add(new SqlParameter("@test", "Hello2"));

            using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required))
            {
                ExecuteNonQuery(command);
                sc.Complete();
            }
        }
    }

    static void Main(string[] args)
    {

        DAL dal = new DAL();
        TransactionOptions tso = new TransactionOptions();
        tso.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;

        using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required,tso))
        {
            dal.FirstMethod();
            dal.SecondMethod();
            sc.Complete();
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2009-04-06 19:32:12

我不认为您的问题与.NET TransactionScope概念有任何关系。相反,这听起来像是在描述SQL Server事务的预期行为。此外,更改隔离级别只会影响“数据读取”,而不会影响“数据写入”。从SQL Server BOL:

“选择事务隔离级别不会影响为保护数据修改而获取的锁。事务始终在其修改的任何数据上获得排它锁,并在事务完成之前一直持有该锁,而不管为该事务设置的隔离级别如何。对于读取操作,事务隔离级别主要定义保护级别,使其不受其他事务所做修改的影响。”

这意味着您可以通过更改发出SELECT语句的客户端的隔离级别来防止阻塞行为。READ COMMITED隔离级别(默认)不会阻止阻塞。为了防止阻塞客户端,您可以使用READ UNCOMMITTED隔离级别,但您必须考虑到这样一种可能性,即可能会检索到已由打开的事务更新/插入的记录(即,如果事务回滚,这些记录可能会消失)。

票数 19
EN

Stack Overflow用户

发布于 2012-04-18 23:12:58

讨论事务是一个好问题。

您的主要方法是保持事务提交。即使您在其他方法中提交,您仍然会在该行上拥有锁。在提交锁定事务之前,您将无法读取该表并提交read COMMITTED。

下面是第一个方法返回后的代码:

在第二个方法返回之后,您将向表中再添加一个锁。

如果我们使用SPID(55)从查询窗口执行select语句,您将看到等待状态。

在您的主方法trans commits之后,您将获得select语句结果,并且它将仅显示我们的select语句查询页面中的共享锁。

X意味着排它锁,IX意图锁。You can read more from my blog post about transactions

如果你想在不等待的情况下阅读,你可以使用nolock提示。如果您想要在第一个方法提交后读取,可以删除外部作用域。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/722528

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档