【问题标题】:Using IsolationLevel.Snapshot but DB is still locking使用 IsolationLevel.Snapshot 但数据库仍处于锁定状态
【发布时间】:2009-06-25 14:07:08
【问题描述】:

我是构建基于 ADO.NET 的网站的团队的一员。有时我们有几个开发人员和一个自动化测试工具同时工作一个数据库的开发副本。

我们使用快照隔离级别,据我所知,它使用乐观并发:而不是锁定,它希望最好,如果受影响的行已被更改,则如果您尝试提交事务,则会引发异常交易过程中的另一方。

要使用我们使用的快照隔离级别:

ALTER DATABASE <database name>
SET ALLOW_SNAPSHOT_ISOLATION ON;

在 C# 中:

Transaction = SqlConnection.BeginTransaction(IsolationLevel.Snapshot);

请注意,IsolationLevel Snapshot 与 ReadCommitted Snapshot 不同,我们也尝试过,但目前没有使用。

当其中一位开发人员进入调试模式并暂停 .NET 应用程序时,他们将在调试时保持与活动事务的连接。现在,我希望这不是问题——毕竟,所有事务都使用快照隔离级别,所以当一个事务暂停时,其他事务应该能够正常进行,因为暂停的事务没有持有任何锁。当然,当暂停的事务完成时,很可能会检测到冲突;但这是可以接受的,只要其他开发人员和自动化测试可以不受阻碍地进行。

然而,实际上,当一个人在调试时暂停事务时,尽管使用了快照隔离级别,但尝试访问相同行的所有其他数据库用户都会被阻止。

有谁知道为什么会发生这种情况,和/或我如何才能实现真正的乐观(非阻塞)并发?

决议(对我来说是一个不幸的决议)Remus Rusanu 指出作家总是阻止其他作家;这得到了MSDN 的支持——它并没有完全说出来,但只提到了避免读写器锁。简而言之,我想要的行为并没有在 SQL Server 中实现。

【问题讨论】:

    标签: sql sql-server ado.net isolation-level


    【解决方案1】:

    SNAPSHOT 隔离级别与所有隔离级别一样仅影响读取。写入仍然相互阻塞。如果您认为您看到的是读取块,那么您应该进一步调查并检查发生阻塞的资源类型和资源名称(sys.dm_exec_requests 中的 wait_type 和 wait_resource)。

    我不建议更改代码以支持开发人员连续数分钟盯着调试器的情况。如果您认为这种情况可以在生产中重复(即客户端挂起),那么情况就不同了。为了实现您想要的,您必须在事务结束时最小化写入并执行所有写入,在返回之前提交的一个调用中。这样没有客户端可以长时间持有 X 锁(不能在持有 X 锁时挂起)。在实践中,这很难实现,并且需要开发人员在编写数据访问代码方面有很多纪律。

    【讨论】:

    • 这种行为在生产中不太可能发生。另一方面,开发版本非常重要,如果能顺利开发,我非常愿意进行代码更改。不幸的是,似乎没有实现“svn-esque”风格的锁定(希望是最好的,只是在冲突中失败)。在不阻塞所有小事务的情况下进行长时间运行和复杂事务的能力仍然有用 - 因为我们使用更少的事务来避免阻塞。
    • 没有灵丹妙药。但是如果你发现自己经常在写和写中被阻塞,你应该考虑为什么会发生这种情况,为什么不同的“请求”会导致相同数据的更新。也许您可以更好地划分您的应用程序,降低重叠的概率。也许某些更新可以延迟,在用户事务期间在工作表中排队(可以使入队/出队成为无块,小心),然后由专用批处理处理。还要确保所有事务只锁定所需的最小值(没有页面/表锁定、没有升级、没有徒劳的表扫描)。
    【解决方案2】:

    当一位开发人员暂停事务时,您是否查看过锁?另外,仅仅开启快照隔离级别并没有太大的影响。您是否将 ALLOW_SNAPSHOT_ISOLATION 设置为 ON?

    步骤如下:

    ALTER DATABASE <databasename>
    SET READ_COMMITTED_SNAPSHOT ON;
    GO
    
    ALTER DATABASE <database name>
    SET ALLOW_SNAPSHOT_ISOLATION ON;
    GO
    

    数据库启用快照隔离后,开发人员和用户必须请求他们的事务在此快照模式下运行。这必须在开始事务之前通过 ADO.NET 事务对象上的客户端指令或在其 Transact-SQL 查询中使用以下语句完成:

    SET TRANSACTION ISOLATION LEVEL SNAPSHOT
    

    拉吉

    【讨论】:

    • 数据库启用了allow_snapshot_isolation。不这样做会导致立即异常;当 allow_snapshot_isolation 关闭时,您不能将隔离级别设置为快照(即,设置隔离级别不会静默失败)。我会更新帖子以反映所需的确切命令,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多