【问题标题】:SQL Server 2008 Problem with SCOPE_IDENTITY()SCOPE_IDENTITY() 的 SQL Server 2008 问题
【发布时间】:2010-04-14 00:00:10
【问题描述】:

我的代码没有更新线程字段。它是空的。有人有什么想法吗?

INSERT INTO [Messages]([Sender], [Receiver], [Job_Number], [Subject], [MessageText], [DateSent])
VALUES(@Sender, @Receiver, @Job_Number, @Subject, @MessageText, @DateSent)

SET @ThreadID = SCOPE_IDENTITY()

UPDATE [Messages] 
SET Thread = @ThreadID
WHERE MessageID = @ThreadID

编辑: 似乎根本没有执行 UPDATE 例程。我什至在 sproc 的末尾添加了以下代码,但没有任何更新。

UPDATE Comments 
SET SomeField = @ThreadID
where SCID = 33

编辑:

/****** Object:  Table [dbo].[Messages]    Script Date: 04/09/2010 12:08:55 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[Messages](
    [MessageID] [int] IDENTITY(1,1) NOT NULL,
    [Sender] [varchar](30) NOT NULL,
    [Receiver] [varchar](30) NOT NULL,
    [Job_Number] [varchar](20) NULL,
    [Subject] [varchar](200) NULL,
    [MessageText] [varchar](max) NULL,
    [DateSent] [datetime] NULL,
    [Thread] [int] NULL,
 CONSTRAINT [PK_Messages] PRIMARY KEY CLUSTERED 
(
    [MessageID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[Messages] ADD  CONSTRAINT [DF_Messages_DateSent]  DEFAULT (getdate()) FOR [DateSent]
GO

编辑: 当我从 Management Studio 执行存储过程时,更新工作正常。当我使用 SQLHelper 调用它时,问题出在我的应用程序中:

SqlHelper.ExecuteNonQuery(ConfigurationManager.ConnectionStrings["Conn"].ConnectionString,
            "spMessagesInsert",
            0,
            message.Sender, 
            message.Receiver,
            message.Job_Number,
            message.Subject,
            message.MessageText,
            message.DateSent
            );

编辑:最终,我更改了程序代码以使用 Linq-to-sql 而不是使用 SqlHelper 调用存储过程。这似乎解决了这个问题。

【问题讨论】:

  • 您确定在 Messages 表中指定了标识列吗?
  • 更具体地说,MessageID 是身份列吗?目前,您似乎正在将新 ID 复制到同一行中的另一列(线程),这似乎毫无意义。
  • 是的,MessageID 是身份列。我这样做是为了对消息进行分组 - 这并非毫无意义。
  • 您能否为该表发布您的确切脚本 DDL?
  • @CodeByMoonlight - 当多行具有相同的 ThreadID(实际上是第一行的 messageID)时,我使用它对消息进行分组。请不要再问它的有效性,因为它不是重点。

标签: sql-server tsql sql-server-2008 identity


【解决方案1】:

您可能不走运,遇到了(臭名昭著的)identity/parallelism bug reported on MS Connect,即 SQL Server 2005 和 2008 上的 now a KB article too

即SCOPE_IDENTITY返回的值是错误的。代码看起来不错,很多人都看过它,那么如果值错误怎么办?这将给出与您报告的相同的症状。

按照文章中的建议尝试插入 OPTION (MAXDOP 1)

我自己也看到过这种情况,所以它并不抽象或罕见。

【讨论】:

    【解决方案2】:

    “当你消除不可能的事情时, 剩下的一切,无论多么不可能, 一定是真的”

    如果我们假设没有错误,那么只有少数几种可能性:

    1. 没有插入或删除该值。我们可以通过在Set @ThreadId = SCOPE_IDENTITY() 之后立即查询来验证这一点
    2. 正在滚动插入事务(例如,来自调用代码事务、来自调用 sp 事务)。我们可以通过查看更新语句前后的@@TRANCOUNT 来验证这一点。
    3. 在您的 Update 语句之后立即将 Thread 列设置为空。我们可以在更新语句之后检查@@ROWCOUNT。如果为零,则唯一的可能是该记录不再存在。如果它是 1,那么显然更新有效。在更新语句之后,您应该能够调用Select * From Messages Where MessageId = @ThreadId And Thread Is Not Null 并获取记录。这意味着,如果稍后您的代码再次为 Null,则其他内容已对其进行了更改。

    尝试以下方法:

    Set NoCount Off
    
    INSERT INTO [Messages]([Sender], [Receiver], [Job_Number], [Subject], [MessageText], [DateSent])
    
    VALUES(@Sender, @Receiver, @Job_Number, @Subject, @MessageText, @DateSent)
    
    SET @ThreadID = SCOPE_IDENTITY()
    
    -- ensure that the value is not null
    Select @ThreadId
    
    -- we should get our record from this query
    Select * From Messages Where MessageId = @ThreadId
    
    UPDATE [Messages] 
    SET Thread = @ThreadID
    WHERE MessageID = @ThreadID
    
    -- we should get 1
    Select @@ROWCOUNT
    
    -- we should get a value
    Select * From Messages Where MessageId = @ThreadId And Thread Is Not Null
    
    -- are we in a transaction?
    Select @@TRANCOUNT
    

    编辑 SQL Server Profiler 是解决此类问题的另一个非常有用的工具。例如,您可以告诉它与其他 SQL 语句一起显示 Rollback Tran completedCommit Tran completed 事件,并查看是否有东西在回滚事务。

    【讨论】:

      【解决方案3】:

      检查消息表中的触发器。


      SET @ThreadID = SCOPE_IDENTITY() 
      
      PRINT convert(varchar(30), @ThreadID)
      
      UPDATE [Messages]  
      SET Thread = @ThreadID 
      WHERE MessageID = @ThreadID 
      

      它打印出你期望的结果吗?

      【讨论】:

        【解决方案4】:

        我以前也遇到过同样的问题。解决方案是在存储过程代码的顶部打开 NOCOUNT(假设它不会对您造成任何不必要的副作用):

        设置编号

        或者,您可以从 SQLHelper 为您使用的连接设置 nocount on。

        除了 nocount 关闭时(即计算行数),我不知道为什么会这样工作的所有详细信息,它似乎“混淆”了以下更新语句(如果我得到更多详细信息,我会更新我稍后的回答)。发生了与您描述的相同的事情...以下 UPDATE 语句从未执行,更重要的是,存储过程意外退出(基于 SQL Profiler 中记录的内容)。

        【讨论】:

        • 您尝试了哪种(或两者兼而有之?)方法?在存储过程的顶部添加 SET NOCOUNT ON,或者从您的连接中设置它?
        • 只是为了澄清...所以,您在 INSERT INTO [Messages]... 语句之前添加了 SET NOCOUNT ON?抱歉,我不确定为什么这不起作用;您的症状与我所经历的似乎相同(并且同样令人沮丧;-)。
        • 是的,我就是这么做的。我已经在这个问题上工作了一段时间了。我将改变调用存储过程的方式。我正在将其更改为通过 LINQ 调用它。
        • 垃圾。 SET NOCOUNT ON 只影响客户端中的 DataAdaptor,与 SQL 代码中的后续处理无关。在这里查看我的问题stackoverflow.com/questions/1483732/set-nocount-on-usage
        • 我同意(除了垃圾部分:-),效果/问题只发生在客户端(例如,DataAdaptors、ODBC 连接等)。在服务器上运行存储过程时不会出现问题,例如。通过管理工作室。
        猜你喜欢
        • 2013-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多