我有一个存储过程从表中获取唯一引用。你传入一个代码,例如'我'对于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表。
答案 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