我遇到了一些看起来很像存储过程中的事务的问题已被回滚,即使我很确定它已被提交,因为输出变量直到提交后才设置,并且用户获取输出变量的值(我知道,因为它们将其打印出来并且我还设置了一个日志表,其中我输入了输出变量的值)。 从理论上讲,有人可以手动删除和更新数据,使其看起来像回滚,但这种可能性极小。
所以,我希望有人能在我的存储过程中发现某种结构性错误。认识BOB:
CREATE procedure [dbo].[BOB] (@output_id int OUTPUT, @output_msg varchar(255) OUTPUT)
as
BEGIN
SET NOCOUNT ON
DECLARE @id int
DECLARE @record_id int
SET @output_id = 1
-- some preliminary if-statements that doesn't alter any data, but might do a RETURN
SET XACT_ABORT ON
BEGIN TRANSACTION
BEGIN TRY
--insert into table A
SET @id = SCOPE_IDENTITY()
--update table B
DECLARE csr cursor local FOR
SELECT [some stuff] and record_id
FROM temp_table_that_is_not_actually_a_temporary_table
open csr
fetch next from csr into [some variables], @record_id
while @@fetch_status=0
begin
--check type of item + if valid
IF (something)
BEGIN
SET SOME VARIABLE
END
ELSE
BEGIN
ROLLBACK TRANSACTION
SET @output_msg = 'item does not exist'
SET @output_id = 0
RETURN
END
--update table C
--update table D
--insert into table E
--execute some other stored procedure (without transactions)
if (something)
begin
--insert into table F
--update table C again
end
DELETE FROM temp_table_that_is_not_actually_a_temporary_table WHERE record_id=@record_id
fetch next from csr into [some variables], @record_id
end
close csr
deallocate csr
COMMIT TRANSACTION
SET @output_msg = 'ok'
SET @output_id = @id
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
SET @output_msg = 'transaction failed !'
SET @output_id = 0
INSERT INTO errors (record_time, sp_name, sp_msg, error_msg)
VALUES (getdate(), 'BOB', @output_msg, error_message())
END CATCH
RETURN
END
我知道,我的用户获得了一个@output_id,即SCOPE_IDENTITY(),并且他还获得了一个'okput'的@output_msg。有没有什么方法可以在没有提交交易的情况下获得这些输出?
谢谢。
答案 0 :(得分:1)
您知道问题是交易不支持对变量进行回滚,因为数据库内部没有数据更改。提交或回滚事务只会对这些数据库对象(表,临时表等)产生影响,而不是变量(包括表变量)。
- 的修改
declare @v1 int = 0, @v2 int = 0, @v3 int = 0
set @v2 = 1
begin tran
set @v1 = 1
commit tran
begin tran
set @v3 = 1
rollback tran
select @v1 as v1, @v2 as v2, @v3 as v3
结果如下
答案 1 :(得分:0)
就我个人而言,我从未在存储过程中使用过交易,特别是当它们被许多人同时使用时。我也很认真地避免使用游标。
我想我会将所涉及的temp_table_that_is_not_actually_a_temporary_table行传递到真正的临时表中,然后将所有行的if语句一起使用。这在tsql中非常简单:
从(normal_table)中选择(数据)到#temp,其中(条件)。
如果说最后一行不符合条件,检查每一行,完成工作然后回滚整个事情的重点是什么?立即检查所有这些,立即为所有人完成工作。这就是sql的全部内容。