【问题标题】:Multythread safety of SQL stored procedureSQL存储过程的多线程安全
【发布时间】:2014-12-22 08:25:22
【问题描述】:

我需要将一些数据存储到数据库中,如果它被读取一次,则将其标记为“已使用”。它应该可以在同时调用 20 多个线程时正常工作。

这个想法是一个线程只能获得它的唯一值,但两个线程不能获得相同的值。对值列表的访问是通过一些 int 键和线程应该使用该键获取任何值,但不是多个线程具有相同的值

我创建了一个具有下一个结构的表

.

所以添加的存储过程很简单

ALTER PROCEDURE [dbo].[StorageAdd]
@key int,
@value nvarchar(100)
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY
        INSERT INTO Storage(k, value, isUsed) VALUES (@key, @value, 0)
        SELECT 1  as 'result', '' as 'message'
    END TRY
    BEGIN CATCH
        SELECT 0 as 'result', 'Operation failed. Message = ' + ERROR_MESSAGE() as 'message'
    END CATCH   
END

但是在它之后我应该执行 SELECT 和 UPDATE 的地方并不那么明显

CREATE PROCEDURE StorageGet
    @key int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

BEGIN TRAN 
BEGIN TRY
    -- create variable for value
    DECLARE @value nvarchar(100)
    -- get first value from database
    SET @value = (SELECT TOP 1 Storage.value FROM Storage WHERE Storage.k = @key AND Storage.isUsed = 0)

    IF(@value IS NULL OR @value = '')
        BEGIN
            ROLLBACK
            SELECT 0 as 'result', 'No items found' as 'message', '' as 'value'
            RETURN
        END

    UPDATE Storage SET Storage.isUsed = 1 WHERE  Storage.k = @key AND Storage.value = @value 

    IF @@ERROR <> 0
        BEGIN
            -- in case of error roll back this transaction
            ROLLBACK
            -- return 0
            SELECT 0 as 'result', 'Insert article ID failed. Error code = ' + CONVERT(varchar(5), @@ERROR) as 'message', '' as 'value'
            RETURN
        END
    COMMIT TRAN
    SELECT 1 as 'result', '' as 'message', @value as 'value'

END TRY
BEGIN CATCH
    -- in case of error roll back this transaction
    ROLLBACK
    -- return 0
    SELECT 0 as 'result', 'Operation failed. Message = ' + ERROR_MESSAGE() as 'error'
    RETURN
END CATCH   

END
GO

那么我的事务会是多线程安全的吗?

首先,我为在更新它使用的行之前和之后未使用的表选择最高值。可能的问题是,如果我同时运行 100 次执行,则 2 个线程可以同时进行选择并获得相同的值,之后两者都会更新这一行。

结果我将有 2 个线程具有相同的值且没有错误。

我的事务线程是否安全?我使用 MS SQL Server 2008 和 2012。

【问题讨论】:

    标签: sql-server multithreading sql-server-2008 transactions sql-server-2012


    【解决方案1】:

    只需在第一个SELECT-statement(您读出值的那个)中添加一个提示,以确保该行被锁定直到事务结束:

    SELECT TOP 1 Storage.value FROM Storage 
    WITH (XLOCK, ROWLOCK)
    WHERE Storage.k = @key AND Storage.isUsed = 0
    

    这应该确保在当前事务结束之前没有其他事务可以读取该行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-15
      • 2020-06-12
      • 1970-01-01
      • 2022-11-21
      • 2010-12-01
      相关资源
      最近更新 更多