7
While @@Fetch_Status = 0
Begin
    INSERT INTO  [server].MyDatabase.dbo.Mytabletobeinserted (

    UPC,
    Sale_date)  
    VALUES(
    @UPC,
    @Sale_date)

    'Inserting the error trapping here'

    IF (@@ERROR <> 0)
    BEGIN
        ROLLBACK TRANSACTION;
        RETURN;
    END 

    Update t_sale_from_pos
    set been_sent = 'y' 
    where UPC = @UPC and sale_date=@sale_date

    Fetch Next from CursorSale
    into 
    @UPC,
    @Sale_date
end
close CursorSale

deallocate CursorSale

这个存储过程每天都使用调度程序运行,并且数据正在通过网络传递。当此存储过程执行时,然后在执行过程中会出现突然的网络超时。这将执行每一行以通过网络发送到其他服务器。


现在,我的问题是:

  • 这将如何影响循环内调用回滚事务的数据?
  • 它会再次读取所有行并将其发送到服务器以进行插入,还是只会读取执行期间失败的行?

需要一些建议。谢谢

4

4 回答 4

6

您可以尝试开始分布式事务分布式事务非常适合这种情况,因为分布式事务旨在跨越两个或更多服务器。通过事务,即使系统崩溃,或者断电,系统仍然能够恢复到其一致状态。

BEGIN DISTRIBUTED TRANSACTION;

BEGIN TRY
    //Your code here to create the cursor.
    While @@Fetch_Status = 0
    Begin
         INSERT INTO  [server].MyDatabase.dbo.Mytabletobeinserted(UPC,Sale_date)  
                                                          VALUES(@UPC,@Sale_date)

         Update t_sale_from_pos
         set been_sent = 'y' 
         where UPC = @UPC and sale_date=@sale_date

         Fetch Next from CursorSale into @UPC,@Sale_date
    END
    close CursorSale

    deallocate CursorSale
END TRY
BEGIN CATCH
    close CursorSale

    deallocate CursorSale

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO

实际上,对于分布式事务,您不需要使用游标。在您的情况下,最好还考虑通过创建临时表来避免并发问题。原因是:插入语句可能需要一些时间,并且在插入数据时,您的表可能会被另一个用户更新,之后发生的更新语句可能会更新错误的行。

BEGIN DISTRIBUTED TRANSACTION;

BEGIN TRY
    CREATE TABLE #LocalTempTable(UPC int,Sale_date datetime)
    INSERT INTO #LocalTempTable(UPC,Sale_date)
    SELECT UPC,Sale_date 
    FROM YourTable

    INSERT INTO [server].MyDatabase.dbo.Mytabletobeinserted(UPC,Sale_date)  
    SELECT UPC,Sale_date 
    FROM #LocalTempTable

    Update t_sale_from_pos
    set been_sent = 'y' 
    where EXISTS (SELECT *
                  FROM #LocalTempTable
                  WHERE #LocalTempTable.UPC = t_sale_from_pos.UPC 
                        AND #LocalTempTable.Sale_date  = t_sale_from_pos.Sale_date)

END
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO
于 2013-06-22T09:11:30.083 回答
2

如果我理解正确的话。TRY/CATCH 应该可以帮助你 -

WHILE @@FETCH_STATUS = 0 BEGIN

     BEGIN TRY

          INSERT INTO [server].MyDatabase.dbo.Mytabletobeinserted (UPC, Sale_date)  
          SELECT @UPC, @Sale_date

          UPDATE dbo.t_sale_from_pos
          SET been_sent = 'y' 
          WHERE UPC = @UPC 
          AND sale_date = @sale_date

     END TRY
     BEGIN CATCH

          UPDATE dbo.t_sale_from_pos
          SET been_sent = 'n' 
          WHERE UPC = @UPC 
          AND sale_date = @sale_date

     END CATCH

     FETCH NEXT FROM CursorSale INTO @UPC, @Sale_date

END

CLOSE CursorSale
DEALLOCATE CursorSale
于 2013-06-20T05:24:38.327 回答
1

我认为你在错误的地方感到困惑,

引用@@fetch_status

这里 ,0 = The FETCH statement was successful.

因此,在获取成功之前,循环将继续,如果发生任何@@error,它将以创建的游标中的所有行结束。如果没有发生错误

CursorSale您在逻辑上是正确的,如果在适当的位置正确定义它,它将正常工作..

有关更多想法,请参阅上述链接中的示例

我希望这会做..

于 2013-06-20T12:14:52.210 回答
0

我建议不要循环每条记录,而是分块进行插入。就像一次 5000 条记录一样,如果这是一项自动化工作,那么这将是可行的。

这是我找到的一个链接,但基本上你每次在上面的循环中都会做前 5000 名。我想如果你有一份工作在每条记录上运行一个游标以进行插入,它可能会变得非常昂贵。

http://social.msdn.microsoft.com/Forums/sqlserver/en-US/1b3dbf8d-252f-43c4-80d6-d5724fe912b4/how-to-insert-rows-in-chunk-size

于 2013-06-27T03:15:40.470 回答