使用IsolationLevel.Snapshot但DB仍然是锁定的

时间:2009-06-25 14:07:08

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

我是构建基于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中实现。

2 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:2)

当一位开发人员暂停交易时,您是否看过锁?此外,仅打开快照隔离级别没有太大影响。你有没有设置ALLOW_SNAPSHOT_ISOLATION?

以下是步骤:

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

拉​​吉