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

时间:2017-11-14 14:19:40

标签: sql sql-server

我有一个存储过程从表中获取唯一引用。你传入一个代码,例如'我'对于itemref或' T'对于tranref,还有其他代码,然后存储过程将查找表,增加数字并返回所述数字(这是其他人可以使用下一个数字等)。

然而,在对象级别(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表。

1 个答案:

答案 0 :(得分:0)

看到一些调用此过程的代码会有所帮助,但您在此处有多个事务。我建议重新使用它来利用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