如何在 SQL Server 中回滚或提交事务

问题描述 投票:0回答:2

在我的存储过程中,我有三个插入语句。

在重复键值插入时,前两个查询会生成错误

违反主键约束

第三个查询照常运行。

现在我希望如果任何查询生成任何异常,一切都应该回滚。

如果任何查询都没有生成任何异常,则应该提交。

declare @QuantitySelected as char
    set @QuantitySelected = 2

    declare @sqlHeader as varchar(1000)
    declare @sqlTotals as varchar(1000)
    declare @sqlLine as varchar(1000)

    select @sqlHeader = 'Insert into tblKP_EstimateHeader '
    select @sqlHeader = @sqlHeader + '(CompanyID,CompanyName,ProjectName,EstimateID,EstimateHeader,QuoteDate,ValidUntil,RFQNum,Revision,Contact,Status,NumConfigurations) '
    select @sqlHeader = @sqlHeader + ' select CompanyID,CompanyName,ProjectName,EstimateID,EstimateHeader,QuoteDate,ValidUntil,RFQNum,Revision,Contact,Status,NumConfigurations '
    select @sqlHeader = @sqlHeader +  'from V_EW_Estimate_Header where EstimateID = 2203'



    select @sqlTotals = 'Insert into tblKP_Estimate_Configuration_Totals '
    select @sqlTotals = @sqlTotals + '(ConfigRecId,RecId,SellQty,ConfigNum,ConfigDesc,SortOrder,OptionsInMainPrice,MarkupPctQty,'
    select @sqlTotals = @sqlTotals + ' SellPriceQty,RubberStamp,OptPriceQty,StatusRecid,LastUpdate_Date,LastUpdate_User,TotalCost,QuantityBracketSelected)'
    select @sqlTotals = @sqlTotals + ' select ConfigRecId,RecId,SellQty' + @QuantitySelected + ',ConfigNum,ConfigDesc,SortOrder,OptionsInMainPrice'
    select @sqlTotals = @sqlTotals + ' ,MarkupPctQty' + @QuantitySelected + ',SellPriceQty' + @QuantitySelected + ',RubberStamp,OptPriceQty' + @QuantitySelected + ',StatusRecid,LastUpdate_Date,LastUpdate_User,TotalCost' + @QuantitySelected + ',' + @QuantitySelected
    select @sqlTotals = @sqlTotals + ' from v_EW_Estimate_Configuration_Totals where ConfigRecId = -3'


    select @sqlLine = 'Insert into tblKP_Estimate_Configuration_Lines'
    select @sqlLine = @sqlLine + '(MstrRfqRecId,RfqRecId,RfqLineRecId,CompanyId,VendorQuoteNum,LineGrp,LineNum,StatusRecId,'
    select @sqlLine = @sqlLine + ' LineDesc,LineSize,LineMatl,LineDeco,LineFinish,CopyFromRecId,PerPieceCost,IsOptional,'
    select @sqlLine = @sqlLine + ' CopyToNewRev,RecId,UnitPrice,LineQty,LinePrice,CustOrVend,SellQty1,RfqNum,ConfigLineIsOptional,ConfigLinePerPieceCost,ConfigLineRecid,SellPrice,SaleQty)'
    select @sqlLine = @sqlLine + ' select distinct MstrRfqRecId,RfqRecId,RfqLineRecId,CompanyId,VendorQuoteNum,LineGrp,LineNum,'
    select @sqlLine = @sqlLine + ' StatusRecId,LineDesc,LineSize,LineMatl,LineDeco,LineFinish,CopyFromRecId,PerPieceCost,IsOptional,'
    select @sqlLine = @sqlLine + ' CopyToNewRev,RecId,UnitPrice' + @QuantitySelected + ',LineQty' + @QuantitySelected + ', isnull(LinePrice' + @QuantitySelected + ', 0.0000),CustOrVend,SellQty' + @QuantitySelected + ',RfqNum,ConfigLineIsOptional,ConfigLinePerPieceCost,ConfigLineRecid,SellPrice' + @QuantitySelected + ',SaleQty' + @QuantitySelected
    select @sqlLine = @sqlLine + ' from v_EW_EstimateLine  where rfqlinerecid in (select RfqLineRecID from kp_tblVendorRfqConfigLine where ConfigRecID = -3) '

    exec( @sqlHeader)
    exec(@sqlTotals)
    exec(@sqlLine)
sql sql-server sql-server-2008 sql-server-2005
2个回答
206
投票

好消息是 SQL Server 中的事务可以跨越多个批次(每个

exec
被视为一个单独的批次。)

您可以将

EXEC
语句包装在
BEGIN TRANSACTION
COMMIT
中,但如果发生任何错误,您需要更进一步并回滚。

理想情况下你想要这样的东西:

BEGIN TRY
    BEGIN TRANSACTION 
        exec( @sqlHeader)
        exec(@sqlTotals)
        exec(@sqlLine)
    COMMIT
END TRY
BEGIN CATCH

    IF @@TRANCOUNT > 0
        ROLLBACK
END CATCH

BEGIN TRANSACTION
COMMIT
相信你已经很熟悉了。
BEGIN TRY
BEGIN CATCH
块基本上用于捕获和处理发生的任何错误。如果任何
EXEC
语句引发错误,代码执行将跳转到
CATCH
块。

您现有的 SQL 构建代码应该位于事务之外(上图),因为您总是希望事务尽可能短。


0
投票

替代方法不需要

TRY...CATCH
。相反,您使用启用
XACT_ABORT
,如果发生错误而不是事务,这将导致整个事务回滚。那么你只需要
COMMIT
最后的交易。

修改来自Code Magiciananswer的简洁代码:

SET XACT_ABORT ON;
BEGIN TRANSACTION 

EXEC sys.sp_executesql @sqlHeader;
EXEC sys.sp_executesql @sqlTotals;
EXEC sys.sp_executesql @sqlLine;

COMMIT;

顺便说一句,构建动态查询的 SQL 应该更新为不开放注入,并参数化对

sys.sp_executesql
的调用。

© www.soinside.com 2019 - 2024. All rights reserved.