2014-08-27 103 views
5

循环可以自锁吗?循环可以自锁吗?

昨晚测试队打开了一个奇怪的勾号。 该应用程序有一个网格,用户可以检查事件推迟 测试者选择了两个事件(IDS:1和5),推迟双方却一个没有拿到状态更新

我知道[事件]做表必须进行更新和一个新的记录在[IncidentDetail表 我查询都与插入喜欢这个:

Id IncidentKindCode TransportEntryId CreateDate    IncidentStatus CloseDate 
-- ---------------- ---------------- ---------------------- -------------- --------- 
1 11301   52    2014-08-26 19:23:21.47 1    NULL 
5 11301   56    2014-08-26 20:06:17.94 0    NULL 

Id IncidentId InsertDate    DetailKind Reason IncidentUser PostponeDate 
-- ----------- ---------------------- ---------- --------- ------------ ----------------------- 
9 1   2014-08-26 20:28:37.37 1   TEST TEST 8   2014-08-27 00:00:00.000 
10 5   2014-08-26 20:28:37.37 1   TEST TEST 8   2014-08-27 00:00:00.000 

测试人员抱怨是有效的,因为这两个[事件] [IncidentStatus]值必须在这个零。点。 挖掘后,我捕获了应用程序发送到服务器的确切查询(感谢探查器)。

declare @p1 int 
set @p1=2 
exec sp_prepexec @p1 output,N'@IDINCIDENT varchar(max) ,@REASON varchar(max) ,@USERCODE varchar(max) ,@POSTPONEDATE varchar(max) ',N' 
DECLARE @ARRAY VARCHAR(8000), @DELIMITADOR VARCHAR(100), @SELECTEDID VARCHAR(8000); 

SELECT @ARRAY = @IDINCIDENT 
SELECT @DELIMITADOR = '';'' 

IF LEN(@ARRAY) > 0 SET @ARRAY = @ARRAY + @DELIMITADOR 

WHILE LEN(@ARRAY) > 0 
BEGIN 

    SELECT @SELECTEDID = LTRIM(SUBSTRING(@ARRAY, 1, 
    CHARINDEX(@DELIMITADOR, @ARRAY) - 1)) 

    BEGIN 
     UPDATE [dbo].Incident SET INCIDENTSTATUS = 1 WHERE ID = @SELECTEDID 
     INSERT [dbo].IncidentDetail (INCIDENTID, DETAILKIND, REASON, INCIDENTUSER, POSTPONEDATE) 
         VALUES (@SELECTEDID, 1, @REASON, @USERCODE, @POSTPONEDATE); 
    END 

    SELECT @ARRAY = SUBSTRING(@ARRAY, 
    CHARINDEX(@DELIMITADOR, @ARRAY) + 1, LEN(@ARRAY)) 
END 
',@IDINCIDENT='1;5',@REASON='querty',@USERCODE='1',@POSTPONEDATE='2014-08-28 00:00:00' 
select @p1 

没有触发器,没有其他更新没有未决事务。 据我所知,即使第一次循环迭代阻止第二次循环到更新失败的位置,也必须引发异常,并且所有事务都要回滚。

似乎ilogical在插入工作时更新可能失败。 所有列都有标准类型(Int,Varchar(100),DateTime等),我也测试了隐式转换问题。

这个问题只发生过一次,即使使用备份也无法复制,但如果我无法找到它发生的原因,恐怕会再次发生。

+0

SQL Server中的错误有时会中止批处理,有时它们不会。交易和连接也一样。 (是的,这很讨厌。);所以你的更新可能会失败,插入可能会通过。也许你的应用程序正在抛出错误。 – usr 2014-08-27 21:04:28

+0

不,事务本身不能阻塞或死锁。 – usr 2014-08-27 21:04:47

+0

内部查询死锁可以并确实发生。我在生产代码中自己遇到了它们: http://blogs.msdn.com/b/bartd/archive/2008/09/24/today-s-annoyingly-unwieldy-term-intra-query-parallel-thread -deadlocks.aspx – Jace 2014-08-28 02:11:34

回答

3

我不明白你究竟想要做什么。我根据我的理解给你一个方法。您可以检查是否更新条目,如果更新,则插入IncidentDetail。

UPDATE [dbo].Incident SET INCIDENTSTATUS = 1 WHERE ID = @SELECTEDID 

If Exists( Select 1 
      From [dbo].Incident As I 
      Where I.ID = @SELECTEDID 
        And I.INCIDENTSTATUS = 1 
     ) 
Begin 
    INSERT [dbo].IncidentDetail (INCIDENTID, DETAILKIND, REASON, INCIDENTUSER, POSTPONEDATE) 
         VALUES (@SELECTEDID, 1, @REASON, @USERCODE, @POSTPONEDATE); 
End 
+0

几天后,我们发现问题是由另一位同事删除了一行引起的,我们盲目地认为这不是问题。此外,我还发现很多参考文献说,循环无法锁定自己(问题从一开始就很愚蠢,我不想关闭它)。我不想删除它作为参考,因为很多人访问过它。还病态upvote你的答案,因为它可以有用的人 – jean 2014-09-24 18:11:26