繁体   English   中英

不同连接上的SQL Server存储过程

[英]SQL Server Stored Procedure on Diferent Connection

我有一个存储过程,可以从表中获得唯一的引用。 您传入一个代码,例如为itemref输入“ I”或为tranref输入“ T”,那么还有其他代码,然后存储过程将查找表,增加数字并返回该数字(这样其他人可以拥有下一个数字等等。)。

但是,在对象级别(vb.net),我想获取不同连接上的引用,该引用永远不会通过在事务中间访问该表来锁定该表。 这一直很好,直到测试时我碰到一些代码,在该代码中另一个存储过程(在发布发票的事务中)也称为get_ref存储过程,这很好,直到对象尝试再次获取它然后锁定系统为止。

是否有一种方法可以使存储过程仅在不同的连接/事务级别上调用另一个存储过程?

这是get_ref存储过程:

CREATE PROCEDURE get_ref 
    (@Ref NUMERIC(28,0) OUTPUT, 
     @RefType VARCHAR(8), 
     @AddVal NUMERIC(28,0) = NULL)
AS
    SET NOCOUNT ON

    DECLARE @VALINC int

    IF @Addval IS NULL
        SET @VALINC = 1
    ELSE
        IF @Addval > 0
            SET @VALINC = @Addval
        ELSE
            SET @VALINC = 1

    IF UPPER(@RefType) = 'HM'
    BEGIN
        BEGIN TRANSACTION
            UPDATE HMREFS 
            SET REF = REF + @valinc

            IF (@@ERROR <> 0)
                GOTO ERRLAB

            SELECT @ref = REF 
            FROM HMREFS

            IF (@@ERROR <> 0)
                GOTO ERRLAB

            COMMIT TRANSACTION
    END
    ELSE
        IF UPPER(@RefType) = 'T'
        BEGIN
            BEGIN TRANSACTION
                UPDATE sysgen 
                SET TRANREF = TRANREF + @valinc

                IF (@@ERROR <> 0)
                    GOTO ERRLAB

                SELECT @ref = TRANREF FROM sysgen

                IF (@@ERROR <> 0)
                    GOTO ERRLAB

                COMMIT TRANSACTION
    END
    ELSE
        IF UPPER(@RefType) = 'I'
        BEGIN
            BEGIN TRANSACTION
                UPDATE sysirgen 
                SET ITEMREF = ITEMREF + @valinc

                IF (@@ERROR <> 0)
                    GOTO ERRLAB

                SELECT @ref = ITEMREF FROM sysirgen

                IF (@@ERROR <> 0)
                    GOTO ERRLAB

                COMMIT TRANSACTION
        END
    RETURN 0

ERRLAB:
    ROLLBACK TRANSACTION
    RAISERROR ('Error Getting Reference', 16, 1)
    RETURN 1
GO

我有与数据库有两个连接的程序。 用于获取引用等的Connection1。这将永远不会使用Begin事务,因为我不想阻止任何其他用户访问相同的表。 用于执行工作的Connection2。

我的程序将获得Connection1上发票的参考,然后在Connection2上开始交易并完成将所述发票存放在SP1中的工作。 但是,由于涉及库存(在某些情况下可能不涉及),因此SP1必须调用SP get_ref,以便它可以插入库存移动线。 然后,这将锁定存储过程get_ref访问的表,直到提交Connection2。 但是,发票已过帐,SP1返回程序。 在我的程序提交Connection2之前,它必须分派货物(如果有),并留在交易中。 然后,它在Connection1上调用引用,该引用已锁定,因为Connection2上的SP1已访问了它想要的表。 然后程序崩溃。

当前及其过去的工作方式是所有工作都在同一个连接上,因此没有死锁问题,除非我们涉及到运行时间较长的流程而其他人也这样做。 在这种情况下,我们将遇到其他人登录时出现的死锁问题。这不是我们经常遇到的问题,但是我们希望对此进行整理。 因此,尝试访问其他事务上的get_ref表。

看到一些代码调用此过程会很有帮助,但是这里有多个事务在进行。 我建议对此进行重做以利用TRY / CATCH。 它使代码易于遵循。 您很有可能挂起了一个事务,这就是导致您之前锁定的原因。

这样的事情。

CREATE PROCEDURE get_ref 
(
    @Ref numeric(28,0) OUTPUT
    , @RefType VARCHAR(8)
    , @AddVal numeric(28,0) = NULL
) AS

    SET NOCOUNT ON;

DECLARE @VALINC int

--rewritten as a case expression below  
--IF @Addval IS NULL
--    SET @VALINC = 1
--ELSE
--    IF @Addval > 0
--        SET @VALINC = @Addval
--    ELSE
--        SET @VALINC = 1

select @VALINC = case when isnull(@AddVal, 0) = 0 OR @AddVal < 0 then 1 else @AddVal end

BEGIN TRY
    BEGIN TRANSACTION

    IF UPPER(@RefType) = 'HM'
        BEGIN
            UPDATE HMREFS SET REF = REF + @valinc
            SELECT @ref = REF FROM HMREFS
        END
    ELSE
        IF UPPER(@RefType) = 'T'
        BEGIN
            UPDATE sysgen SET TRANREF = TRANREF + @valinc
            SELECT @ref = TRANREF FROM sysgen
        END
    ELSE
        IF UPPER(@RefType) = 'I'
        BEGIN
            UPDATE sysirgen SET ITEMREF = ITEMREF + @valinc
            SELECT @ref = ITEMREF FROM sysirgen
        END
    COMMIT TRANSACTION
    --there is no point in returning 0, that is the default return value when a procedure completes without error
END TRY

BEGIN CATCH
    ROLLBACK TRANSACTION
    RAISERROR ('Error Getting Reference', 16, 1)
    RETURN 1
END CATCH

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM