5

我有两个事务:具有SERIALIZABLE隔离级别的 T1 和 T2(我认为 - 具有默认READ COMMITTED隔离级别,但没关系)。

SELECT然后事务 T1 执行WAITFOR2 秒SELECT

事务 T2UPDATE对 T1 读取的数据执行。

它导致死锁,为什么事务 T2 不等待 T1 结束?

当 T1 具有REPEATABLE READ隔离级别时,一切正常,即出现幻像行。我以为当我将隔离级别提高到 时SERIALIZABLE,T2 将等待 T1 结束。

这是我大学运动的一部分。我必须在两个具有不正确隔离级别的并行事务中显示负面影响,并且在正确的隔离级别下不存在这些影响。

这是代码,不幸的是,字段名称是波兰语。

T1:

使用先生;

SET IMPLICIT_TRANSACTIONS 关闭;
设置事务隔离级别可序列化;

开始交易;

-- 1. 扎皮塔尼
选择
    www.IdSamochodu, s.Model, s.Marka, s.NrRejestracyjny, o.PESEL, o.Nazwisko, o.Imie, o.NrTelefonu
从
    WizytyWWarsztacie www
加入
    萨摩奇
    ON s.IdSamochodu = www.IdSamochodu
加入
    奥索比
    ON o.PESEL = s.PESEL
在哪里
    www.[状态] = 'gotowy_do_odbioru'
由 www.IdSamochodu ASC 订购
;

等待延迟'00:00:02';

-- 2. 扎皮塔尼
选择
    u.IdSamochodu,tu.Nazwa,tu.Opis,u.Oplata
从
    乌斯鲁吉乌
加入
    TypyUslug tu
    ON tu.IdTypuUslugi = u.IdTypuUslugi
加入
    WizytyWWarsztacie www
    在 www.IdSamochodu = u.IdSamochodu 和
        www.DataOd = u.DataOd
在哪里
    www.[状态] = 'gotowy_do_odbioru'
由 u.IdSamochodu ASC、u.Oplata DESC 订购
;

犯罪;

T2:

使用先生;

SET IMPLICIT_TRANSACTIONS 关闭;
将事务隔离级别设置为已提交;

开始交易;

更新
    乌斯鲁吉
放
    [状态] = 'wykonano'
在哪里
    IdUslugi = 2
;

更新
    万维网
放
    www.[状态] = 'gotowy_do_odbioru'
从
    WizytyWWarsztacie www
在哪里
    www.[状态] = 'wykonywanie_usług' AND
    存在(
        选择 1
        从
            乌斯鲁吉乌
        在哪里
            u.IdSamochodu = www.IdSamochodu 和
            u.DataOd = www.DataOd AND
            u.[状态] = 'wykonano'
        由 u.IdSamochodu、u.DataOd 分组
        有计数(u.IdUslugi)=(
            选择
                计数(u2.IdUslugi)
            从
                乌斯鲁吉 u2
            在哪里
                u2.IdSamochodu = www.IdSamochodu 和
                u2.DataOd = www.DataOd
            由 u2.IdSamochodu、u2.DataOd 分组
        )
    )
;

犯罪;

我使用 SQL Management Studio,每个事务都在不同的文件中。我通过在 T1 中单击 F5 来运行它,然后快速切换到包含 T2 的文件,然后再次 - F5。

我在 mssql 中阅读了有关死锁和锁定机制的信息,但显然,我还没有理解这个主题。

SQL Server 2008 R2(.Net 2.0 应用程序)中的死锁问题

选择/更新或多选之间的 SQL Server 死锁

SELECT/UPDATE 死锁

http://msdn.microsoft.com/en-us/library/ms173763(v=sql.105).aspx

http://www.sql-server-performance.com/2004/advanced-sql-locking/

编辑

我发现 T2 中的第一个 UPDATE 语句导致了问题,为什么?

4

4 回答 4

6

解决死锁问题从获取死锁图开始。这是一个 xml 文档,它告诉您有关所涉及的事务和资源的相关信息。您可以通过 Profiler、扩展事件或事件通知来获取它(我确信还有其他方法,但现在就可以了)。获得图表后,检查它以查看每个事务在哪些资源上具有哪些类型的锁。你从那里去哪里真的取决于图表中发生的事情,所以我会停在那里。底线:获取死锁图并挖掘它以获取详细信息。

顺便说一句,说一个或另一个事务“导致”死锁有点误导。死锁中涉及的所有事务都是导致死锁情况所必需的,因此两者都没有更多的错误。

于 2013-01-12T21:48:25.157 回答
1

我的 SQL Managmenet Studio 有一些问题(Profiler 没有工作),但最后我得到了deadlock graph这篇文章对我很有帮助。

僵局

为了理解这个图表,我必须了解锁定机制和符号。
我认为这里解释得很清楚。

现在,当我知道所有这些东西时,死锁的原因就很明显了。
我已经为所描述的情况制作了序列图:

序列图

正如我之前写的,当我们从事务 T2 中删除第一个 UPDATE 语句时,不会发生死锁。

在这种情况下,T2 不会在pk_uslugi索引上获得锁,因此来自事务 T1 的第二个 SELECT 语句将成功执行并且索引pk_wizytywwarsztacie将被解锁。在那之后,T2也将完成。

于 2013-01-13T22:26:03.407 回答
0

问题可能是这样的:

  1. T1 Select S 锁定行
  2. T2 更新 U 锁定行(成功)
  3. T2 更新 X 锁定行(等待,锁定排队)
  4. T2 再次尝试 S-lock,但 S-lock 与排队的 X-lock 不兼容。

SQL Server 中的锁是排队的。如果队列的头在等待,那么它后面的所有其他东西也会等待。

实际上,我不完全确定这是原因因为REPEATABLE READ. 我仍在发布这个想法,希望它有所帮助。

于 2013-01-12T21:59:54.020 回答
0

我遇到了类似的问题,我从可用项目列表中进行选择,然后将这些项目插入到保留队列表中。当我有太多并发请求时,select 语句将返回在另一个并行请求期间也同时选择的项目。当尝试将它们插入到保留队列表中时,我会收到一个唯一约束错误(因为同一项目不能两次进入保留表)。

然后我尝试围绕整个事物包装一个 SERIALIZABLE 事务,但后来我遇到了 DEADLOCK 错误,因为两个事务都持有 UC 索引上的锁(由我的死锁图确定)。

我终于能够通过在 select 语句中使用排他行锁来解决这个问题。

您可以尝试在有问题的表/行上使用排他行锁。这将确保 T1 中的行上的锁定将在 T2 尝试更新相同的行之前完成。

例子:

SELECT *
FROM Uslugi u WITH (XLOCK, ROWLOCK)

我还不确定这对性能的影响,但是在使用多个线程运行负载测试时,它似乎没有负面影响。

于 2013-04-23T00:18:31.147 回答