SQL Server从事务外部错误回滚事务

SQL Server从事务外部错误回滚事务,sql,sql-server,sql-server-2012,Sql,Sql Server,Sql Server 2012,我有一个TRY-CATCH语句,其中TRY中的事务中有一些代码,TRY中的事务之外有其他代码。如果事务之外的代码(仍在TRY中)抛出错误,则我的事务不会在CATCH中回滚。但是,如果我删除了事务外部的代码,如果出现错误,事务将回滚。为什么会这样?SQL Server 2014 我的密码。如果远程进程抛出错误,则事务不会回滚: BEGIN try begin transaction INSERT INTO bos_south_florida_job_map (job_id, origina

我有一个TRY-CATCH语句,其中TRY中的事务中有一些代码,TRY中的事务之外有其他代码。如果事务之外的代码(仍在TRY中)抛出错误,则我的事务不会在CATCH中回滚。但是,如果我删除了事务外部的代码,如果出现错误,事务将回滚。为什么会这样?SQL Server 2014

我的密码。如果远程进程抛出错误,则事务不会回滚:

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
这将回滚事务:

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

回想一下,每个
开始事务
@@Trancount
增加1,每个
提交
将其减少1

在第一个示例中,事务已经提交,
@@tracount
在抛出错误之前减少为零,因此在
Catch
子句中,
@@tracount
将为零。这很好。提交的事务已经是历史记录,无法回滚

在第二个示例中,当在
Begin
之后但在
Commit
之前引发错误时,当到达
Catch
子句并回滚时,
@@TranCount
为1

大概您想要的行为是远程调用中的错误会导致回滚?这可以通过在远程调用后将
Commit
移动到,使其成为
End Try
之前的最后一条语句来实现

但是请注意,跨服务器事务相对昂贵,需要在两台服务器上运行MS DTC。DBA可能不赞成在负载沉重的服务器上这样做


顺便说一句,围绕单个插入的事务通常是毫无意义的。正常行为是“自动提交”模式,这意味着insert/update/delete语句是

感谢您的回答,这是有意义的。跨服务器事务正是我试图避免的,但这似乎是我寻找的行为的唯一选项。不,等等,还有另一个选项!您可以先运行外部服务器exec,并且只有在外部服务器调用成功时才运行本地insert?我需要它按此顺序运行,就像在翻转场景中一样。如果insert失败,我不希望执行远程过程。我认为我唯一的选择是“手动回滚”远程进程,通过更新/删除来逆转它所做的更改。事实上,我确实找到了解决方法。如果我将链接服务器的Enable Promotion of Distributed Transactions for RPC属性设置为false,则可以将远程调用放在提交传输之前。