简体   繁体   English

SQL Server回滚事务来自外部事务错误

[英]SQL Server Rollback Transaction From Error Outside Transaction

I have a TRY CATCH statement, where there is some code in a transaction in the TRY, and other code outside of the transaction in the TRY. 我有一个TRY CATCH语句,其中TRY中事务中有一些代码,而TRY中事务中有其他代码。 If the code outside the transction (still in TRY) throws an error, my transaction does not get rolled back in the CATCH. 如果转换之外的代码(仍在TRY中)抛出错误,则我的事务不会在CATCH中回滚。 If I, however, remove the code outside of the transaction, if there is an error the transaction will get rolled back. 但是,如果我删除了事务外的代码,则如果出现错误,事务将被回滚。 Why does this behave this way? 为什么这样表现呢? SQL Server 2014. SQL Server 2014。

My Code. 我的代码。 If Remote proc throws error, the transaction does not get rolled back: 如果Remote proc引发错误,则事务不会回滚:

BEGIN  try
begin transaction

  INSERT INTO bos_south_florida_job_map (job_id, original_job_id, 
created_date, updated_date,completed_status_sent_ind, 
assigned_status_sent_ind, status_prev)
VALUES (9999, '1234', getdate(), getdate(),0,0,'CREATED');


COMMIT TRANSACTION

declare @sql varchar(max)

set @sql = ''

select @sql = '
   declare @error1 varchar(255),
   @error2 varchar(255),
   @error3 varchar(255)

   Exec NEXTGEN.DBO.wbAf_ConfirmDispatchedReservation ''AFFWEB'', ''A10596'', ''Admin'', ''Admin'', '''+cast(preassignedsubconcode as varchar(100))+''', '''+cast('1234' as varchar(20))+''', '''+convert(char(23),ISNULL(ScheduledDispatchDateTime,''),121)+''', '+cast('1234' as varchar(12))+',null,@error1 output,@error2 output,@error3 output

   if @error1 is not null or @error2 is not null or @error3 is not null
   begin
        set @error1 = @error2 + '' '' + @error3 + '' '' + @error1
        RAISERROR (@error1, 16, 1)
   end
   '
from [BCCUATWSQL290].NEXTGEN.DBO.tbRideResCurDispatch
where resno = '35002616'

   exec(@sql) at [BCCUATWSQL290]

END TRY

BEGIN CATCH

IF @@TRANCOUNT > 0  
ROLLBACK TRANSACTION

DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE()

INSERT INTO bos_south_florida_error_log (original_job_id, [action], 
error_datetime, [error_message])
SELECT
    '1234',
    'CREATE_JOB',
    GETDATE(),
    'Msg: ' + ISNULL(CONVERT(VARCHAR, ERROR_NUMBER()), 'N/A') + ', Level: ' + ISNULL(CONVERT(VARCHAR, @ErrorSeverity), 'N/A') + ', Line: ' + ISNULL(CONVERT(VARCHAR, ERROR_LINE()), 'N/A') + ', Error: ' + ISNULL(@ErrorMessage, 'N/A')


END CATCH

This will rollback the transaction: 这将回滚事务:

BEGIN  try
begin transaction

  INSERT INTO bos_south_florida_job_map (job_id, original_job_id, 
created_date, updated_date,completed_status_sent_ind, 
assigned_status_sent_ind, status_prev)
VALUES (9999, '1234', getdate(), getdate(),0,0,'CREATED');

RAISERROR ('BLAH', 16, 1)

COMMIT TRANSACTION

END TRY

BEGIN CATCH

IF @@TRANCOUNT > 0  
ROLLBACK TRANSACTION

DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;

SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE()

INSERT INTO bos_south_florida_error_log (original_job_id, [action], 
error_datetime, [error_message])
SELECT
    '1234',
    'CREATE_JOB',
    GETDATE(),
    'Msg: ' + ISNULL(CONVERT(VARCHAR, ERROR_NUMBER()), 'N/A') + ', Level: ' + ISNULL(CONVERT(VARCHAR, @ErrorSeverity), 'N/A') + ', Line: ' + ISNULL(CONVERT(VARCHAR, ERROR_LINE()), 'N/A') + ', Error: ' + ISNULL(@ErrorMessage, 'N/A')


END CATCH

Recall that every Begin Transaction increases @@Trancount by 1 and every Commit decreases it by 1. 回想一下,每个Begin Transaction@@Trancount增加1,而每个Commit将其减少1。

In your first example, the transaction is already committed and @@TranCount is reduced to zero before you throw the error, so in the Catch clause, @@Trancount will be zero. 在第一个示例中,事务已经提交,并且在引发错误之前@@TranCount减小为零,因此在Catch子句中, @@Trancount将为零。 This is good. 很好 A committed transaction is already history, it can't be rolled back. 提交的事务已经是历史记录,无法回滚。

In your second example when you raise the error after Begin but before Commit , then @@TranCount is 1 when you reach the Catch clause, and you rollback. 在第二个示例中,当您在Begin之后但在Commit之前引发错误时,到达Catch子句并回滚时, @@TranCount为1。

Presumably the behaviour you want is that an error in the remote call should cause a rollback? 大概您想要的行为是远程调用中的错误应导致回滚? Which you can achieve by moving the Commit to after the remote call, making it the very last statement before End Try . 您可以通过在远程调用之后将Commit移至该位置,使其成为End Try之前的最后一条语句来实现。

Note however that cross-server transactions are relatively expensive, and require MS DTC to be running on both servers. 但是请注意,跨服务器事务比较昂贵,并且要求MS DTC在两个服​​务器上都运行。 DBAs may frown upon doing that on heavily-loaded servers. 在负载很重的服务器上,DBA可能不愿这样做。

Btw, a transaction around a single insert is usually pointless. 顺便说一句,围绕单个插入的事务通常是没有意义的。 Normal behaviour is 'autocommit' mode, which means insert/update/delete statements are 'bounded by an unseen BEGIN TRANSACTION and an unseen COMMIT TRANSACTION statement' 正常行为是“自动提交”模式,这意味着插入/更新/删除语句“被看不见的BEGIN TRANSACTION和看不见的COMMIT TRANSACTION语句限制”

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

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