如果用户尝试从多台计算机插入,则阻止插入 [已关闭]

Prevent insert if user trying to insert from multiple computers [closed]

提问人:Saman Khan1 提问时间:11/17/2023 最后编辑:Saman Khan1 更新时间:11/17/2023 访问量:90

问:


编辑问题以包括所需的行为、特定问题或错误以及重现问题所需的最短代码。这将帮助其他人回答这个问题。

4天前关闭。

我有一张表,在为任何用户插入之前,我都会进行一些检查。我使用存储过程进行数据插入。有问题 如果用户使用两台计算机并尝试几乎同时插入(同时单击两台计算机中的“插入”按钮)。他们可以通过检查并插入无效数据。我怎样才能预防它们?

我尝试在插入语句之前在存储过程中进行检查,但仍然不起作用。
我还使用了交易块。

程序如下:

BEGIN TRAN
    IF 
        (
            (
            SELECT SUM(Weight) FROM table
            WHERE 
                MojavezCode = @certId   AND 
                goodsTypeId = @goodType AND 
                isDeleted   = 0         AND 
                DateSabt BETWEEN @StartDore AND @EndDore
            ) 
            > @sahmiye
        )
    BEGIN
        RAISERROR ('---',15,18)
        RETURN   -9523
    END

    INSERT INTO table
    (
       FromKharidarID,
       AmelKharidID,
       DateSabt,
       TimeSabt,
       MojavezCode,
       
       isDeleted,
       goodsTypeId,
       InsertUserIp,
       UniqID,
       Weight

       
    )
    VALUES
    (  @kharidarId,    
       @EtehadyeId,    
        ( SELECT dbo.SolarDate(CONVERT(NVARCHAR(10), GETDATE(), 111))),  
        ( SELECT CONVERT(NVARCHAR(12), GETDATE(), 108)),  
        LTRIM(RTRIM(@certId)) ,  
           
       0, 
       @goodType  ,   
       LTRIM(RTRIM(@userIP)), 
       @uniqueId,
       @Wight
        )
    COMMIT TRAN
sql sql-server t-sql

评论

0赞 Dai 11/17/2023
USE XACT_ABORT ON; BEGIN TRANSACTION txn; /* do stuff */ COMMIT TRANSACTION txn;
0赞 Saman Khan1 11/17/2023
插入仍然发生,因为事务内部没有问题,问题是来自两台不同计算机的两次同时尝试,我无法阻止它们。
0赞 Panagiotis Kanavos 11/17/2023
您描述的是代码中的一个错误,该错误不会通过限制旨在同时处理数百个客户端的服务器来修复。至少发布存储过程代码以及如何调用它
0赞 Saman Khan1 11/17/2023
存储过程非常简单,只有一个插入。
1赞 Panagiotis Kanavos 11/17/2023
然而它失败了。如果它执行检查,它不仅仅是一个插入。发布代码,而不是让人们猜测。那些适用于一个呼叫但不适用于另一个呼叫的检查有些奇怪。他们的陈述可能是错误的,或者检查可能是错误的。或者它们应该在触发器中执行。或者,您可能使用了错误的隔离级别

答:

1赞 Charlieface 11/17/2023 #1

您需要有关子查询的提示,否则它不会锁定这些行。您还应该使用 和 来确保正确的回滚。WITH (HOLDLOCK, UPDLOCK)IFSET XACT_ABORT ONTHROW

SET XACT_ABORT ON;

BEGIN TRAN;
IF (
       (
            SELECT SUM(Weight)
            FROM table WITH (HOLDLOCK, UPDLOCK)
            WHERE 
                MojavezCode = @certId   AND 
                goodsTypeId = @goodType AND 
                isDeleted   = 0         AND 
                DateSabt BETWEEN @StartDore AND @EndDore
       )
       > @sahmiye
   )
BEGIN
    THROW 50001, N'---', 1;
END;

INSERT INTO table
    (
       FromKharidarID,
       AmelKharidID,
       DateSabt,
       TimeSabt,
       MojavezCode,
       isDeleted,
       goodsTypeId,
       InsertUserIp,
       UniqID,
       Weight
    )
    VALUES
    (  @kharidarId,    
       @EtehadyeId,    
        ( SELECT dbo.SolarDate(CONVERT(NVARCHAR(10), GETDATE(), 111))),  
        ( SELECT CONVERT(NVARCHAR(12), GETDATE(), 108)),  
        LTRIM(RTRIM(@certId)) ,  
       0, 
       @goodType  ,   
       LTRIM(RTRIM(@userIP)), 
       @uniqueId,
       @Wight
    );

COMMIT TRAN;

顺便说一句:您不应该将日期和时间存储在单独的字段中,而应该只使用 .你当然不应该把它们存放在田里。datetime2nvarchar

评论

0赞 Dai 11/17/2023
零件的目的是什么?总体上,颠倒逻辑来保护不是更好吗?还是做 ?THROW 50001, N'---', 1;IFINSERTINSERT INTO t ( ... ) SELECT x.a, x.b, x.c WHERE NOT EXISTS( SELECT TOP 1 1 FROM t )
0赞 Charlieface 11/17/2023
THROW将立即结束批处理,因此它会保护它。是的,您可以这样做,但是您没有自定义错误消息。