这个存储过程是否是线程安全的?(或SQL Server上的等价物)

ser*_*ist 6 sql t-sql sql-server sql-server-2005 thread-safety

在其他人的帮助下,我今天早上敲了几张桌子和存储过程,因为我远离数据库程序员.

有人会介意盯着这个并告诉我它是否是线程安全的吗?我想这可能不是DBA/DB开发人员使用的术语,但我希望你能得到这个想法:基本上,如果这个sp正在执行而另一个同时出现会发生什么?一个人会干扰另一个吗?这甚至是SQL/SP中的一个问题吗?

CREATE PROCEDURE [dbo].[usp_NewTicketNumber]
    @ticketNumber int OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    INSERT INTO [TEST_Db42].[dbo].[TicketNumber]
               ([CreatedDateTime], [CreatedBy])
         VALUES
                (GETDATE(), SUSER_SNAME())
    SELECT @ticketNumber = IDENT_CURRENT('[dbo].[TicketNumber]');
    RETURN 0;
END
Run Code Online (Sandbox Code Playgroud)

Dav*_*all 17

您可能不希望使用IDENT_CURRENT - 这会在任何会话和任何范围内返回在相关表上生成的最新标识.如果其他人在错误的时间插入,您将获得他们的ID!

如果要获取刚刚执行的插入生成的标识,则最好使用OUTPUT子句来检索它.过去通常使用SCOPE_IDENTITY(),但在并行执行计划下存在问题.

线程安全的主要SQL等价物是执行多个语句时会导致意外或不良行为.我能想到的这种行为的两种主要类型是锁定(特别是死锁)和并发问题.

当语句阻止其他语句访问它正在使用的行时,会发生锁定问题.这可能会影响性能,在最坏的情况下,两个语句会进行无法协调的更改并发生死锁,从而导致一个语句被终止.

但是,除非涉及其他内容(如数据库事务),否则像您所拥有的简单插入不应导致锁定.

并发问题(描述它们非常糟糕)是由对数据库记录的一组更改覆盖对相同记录的其他更改引起的.同样,插入记录时这不应该是一个问题.


小智 7

最安全的方法可能是使用Output子句,因为在某些情况下(多/并行处理)scope_idendity中存在已知错误.

CREATE PROCEDURE [dbo].[usp_NewTicketNumber]
AS
BEGIN
  DECLARE @NewID INT

  BEGIN TRANSACTION
  BEGIN TRY
    declare @ttIdTable TABLE (ID INT)
    INSERT INTO 
      [dbo].[TicketNumber]([CreatedDateTime], [CreatedBy])
    output inserted.id into @ttIdTable(ID)
    VALUES
      (GETDATE(), SUSER_SNAME())

    SET @NewID = (SELECT id FROM @ttIdTable)

    COMMIT TRANSACTION
  END TRY
  BEGIN CATCH
    ROLLBACK TRANSACTION
    SET @NewID = -1
  END CATCH

  RETURN @NewID
END
Run Code Online (Sandbox Code Playgroud)

这样您应该是线程安全的,因为output子句使用insert实际插入的数据,并且您不会在范围或会话之间遇到问题.