是否可以将 DependentTransaction 或多个 DependentTransactions 与 TPL/并行性一起使用?

发布于 2024-11-29 13:19:18 字数 1494 浏览 1 评论 0原文

我找不到任何与我正在做的事情类似的东西,并且由于预算问题,我必须向你们所有人寻求帮助。我目前正在编写一个导入应用程序,可以导入可变数量的记录。这个可变数字很可能会非常高,可能达到数百万。我们利用 WCF 流将数据块发送到服务器进行处理。在服务器端,我们将数据转储到临时 SQL 表中进行验证。从那里,使用 TPL 提取一定数量的记录,然后将它们插入到永久 SQL 存储库中。涉及的内容还有很多,但简而言之,这就是其中的大部分。目前唯一未解决的问题是我们允许用户随时取消导入。这意味着在保存这些记录期间可能会发生取消。我们需要能够回滚所有插入/更新的记录。由于我们使用 TPL 来处理记录,因此我在共享交易时遇到了极大的困难。我正在使用 MSDN 上概述的 DependentTransaction 方法(非常相似, http://msdn.microsoft.com/en-us/library/system.transactions.dependenttransaction(v=VS.100).aspx)。以下是一些代码片段:

var currentTransaction = System.Transactions.Transaction.Current;

...

// DataTable is simply a placeholder for X amount of records from the SQL temp table
var partitions = Partitioner.Create(0, DataTable.Rows.Count, 100);
Parallel.ForEach(partitions, (partition, state) =>
                    {
                        using (var parallelTransaction = new TransactionScope(currentTransaction.DependentClone((DependentCloneOption.RollbackIfNotComplete)))

在这个 TPL 迭代中,发生了许多选择、插入和更新。如果可能的话,我希望这些都发生在同一事务下。或者至少可以通过 TransactionScope 进行管理,以便我们可以回滚所有内容。我不断收到“事务上下文已在使用中”的错误,然后它几乎立即中止。

我没有正确使用 DependentTransaction 吗?我的要求可以实现吗?我知道事务通常是顺序的,并且不会在这种情况下使用,但为了简单起见并帮助我们不必实现一些疯狂的功能来跟踪插入的记录并手动回滚,事务将是理想的选择!

有什么建议吗?

注意:我尝试使用本地状态方法进行并行迭代,但无论我做什么,都会生成相同的异常。此外,使用 RollbackIfNotComplete 或 BlockCommitUntilComplete 也没有影响。

I haven't been able to find anything remotely similar to what I am doing and due to budget concerns, I have to turn to you all for some assistance. I am currently writing an import application that can import a variable amount of records. More than likely, this variable number will be very high, potentially in the millions. We utilize WCF streaming to send chunks of data to the server for processing. On the server end, we dump the data into a temp SQL table for validation. From there, using TPL to extract a set number of records and then insert them into the permanent SQL storage repository. There's a lot more involved, but in a nutshell that is the bulk of it. The only outstanding issue at this time is that we allow the user to cancel the import at anytime. This means that the cancel could occur during the saving of these records. We need to be able to rollback all of the inserted/updated records. Since we are using TPL to process the records, I am having an extremely difficult time sharing the transactions. I am using the DependentTransaction approach outlined on MSDN (very similar, http://msdn.microsoft.com/en-us/library/system.transactions.dependenttransaction(v=VS.100).aspx). Here are some code snippets:

var currentTransaction = System.Transactions.Transaction.Current;

...

// DataTable is simply a placeholder for X amount of records from the SQL temp table
var partitions = Partitioner.Create(0, DataTable.Rows.Count, 100);
Parallel.ForEach(partitions, (partition, state) =>
                    {
                        using (var parallelTransaction = new TransactionScope(currentTransaction.DependentClone((DependentCloneOption.RollbackIfNotComplete)))

Inside this TPL iteration, there are many selects, inserts and updates occurring. I want these all to occur under the same transaction if possible. Or at least be manageable by a TransactionScope so that we can roll everything back. I keep getting the error that the "transaction context is already in use" and then it aborts, pretty much instantly.

Am I not using the DependentTransaction properly? Can my request even be possible? I know that transactions are typically sequential and are not used in this context, but for simplicity and to help us from having to implement some crazy functionality to keep track of inserted records and rolling-back manually, a transaction would be ideal!

Any suggestions?

NOTE: I have tried using the local state approach to the Parallel iteration, but no matter what I do, it all generates the same exception. Also, using RollbackIfNotComplete or BlockCommitUntilComplete has no bearing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

冷夜 2024-12-06 13:19:18

管理 SQL Server 事务的最佳位置是在 T-SQL 代码中。由于您已经拥有想要在同一个 SQL Server 中插入/更新/删除的所有数据,因此我认为没有任何充分的理由不在 T-SQL 代码的事务中执行选择/插入/更新。这是您可以使用的简单模板。

    -- REFERENCE: http://aleemkhan.wordpress.com/2006/07/21/t-sql-error-handling-pattern-for-nested-transactions-and-stored-procedures/
    -- ======================================================================================
    -- STANDARD HEADER FOR TRANSACTION LOGIC THAT WILL ALSO HANDLE BEING A NESTED TRANSACTION
    -- FOR SQL 2005 AND UP
    -- ======================================================================================
    SET XACT_ABORT ON;
    BEGIN TRY
    DECLARE @TranStarted bit; SET @TranStarted = 0
    IF( @@TRANCOUNT = 0 ) BEGIN  BEGIN TRANSACTION; SET @TranStarted = 1;  END ELSE SET @TranStarted = 0
    -- ======================================================================================




    -- ==================================================================
    -- ***** SQL CODE FOR SELECTS/INSERTS/UPDATES/DELETES GOES HERE *****
    -- ==================================================================




    -- ======================================================================================
    -- STANDARD FOOTER FOR TRANSACTION LOGIC THAT WILL ALSO HANDLE BEING A NESTED TRANSACTION 
    -- FOR SQL 2005 AND UP
    -- ======================================================================================
    IF( @TranStarted = 1 AND (XACT_STATE()) = 1 ) BEGIN  SET @TranStarted = 0; COMMIT TRANSACTION;  END
    RETURN(0)
    END TRY
    BEGIN CATCH
      DECLARE @ErrorMessage  nvarchar(4000)
             ,@ErrorNumber   int
             ,@ErrorSeverity int
             ,@ErrorState    int;
       SELECT @ErrorMessage  = ERROR_MESSAGE() + CHAR(13) + 'Actual Code Line that took the error: ' + CONVERT(nvarchar, ERROR_LINE())
                                               + CHAR(13) + 'Actual Proc that took the error: ' + CONVERT(nvarchar(126), ERROR_PROCEDURE())
             ,@ErrorSeverity = ERROR_SEVERITY()
             ,@ErrorState    = ERROR_STATE()
             ,@ErrorNumber   = ERROR_NUMBER();

    IF( @TranStarted = 1 AND (XACT_STATE()) = -1 ) BEGIN  SET @TranStarted = 0; ROLLBACK TRANSACTION; END
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
    END CATCH
    -- ======================================================================================

The best place to manage SQL Server transactions is within T-SQL code. Since you already have all the data you want to insert/update/delete in the same SQL Server, I don't see any good reason not to just perform your selects/inserts/updates within a transaction in T-SQL code. Here is a simple template you can use.

    -- REFERENCE: http://aleemkhan.wordpress.com/2006/07/21/t-sql-error-handling-pattern-for-nested-transactions-and-stored-procedures/
    -- ======================================================================================
    -- STANDARD HEADER FOR TRANSACTION LOGIC THAT WILL ALSO HANDLE BEING A NESTED TRANSACTION
    -- FOR SQL 2005 AND UP
    -- ======================================================================================
    SET XACT_ABORT ON;
    BEGIN TRY
    DECLARE @TranStarted bit; SET @TranStarted = 0
    IF( @@TRANCOUNT = 0 ) BEGIN  BEGIN TRANSACTION; SET @TranStarted = 1;  END ELSE SET @TranStarted = 0
    -- ======================================================================================




    -- ==================================================================
    -- ***** SQL CODE FOR SELECTS/INSERTS/UPDATES/DELETES GOES HERE *****
    -- ==================================================================




    -- ======================================================================================
    -- STANDARD FOOTER FOR TRANSACTION LOGIC THAT WILL ALSO HANDLE BEING A NESTED TRANSACTION 
    -- FOR SQL 2005 AND UP
    -- ======================================================================================
    IF( @TranStarted = 1 AND (XACT_STATE()) = 1 ) BEGIN  SET @TranStarted = 0; COMMIT TRANSACTION;  END
    RETURN(0)
    END TRY
    BEGIN CATCH
      DECLARE @ErrorMessage  nvarchar(4000)
             ,@ErrorNumber   int
             ,@ErrorSeverity int
             ,@ErrorState    int;
       SELECT @ErrorMessage  = ERROR_MESSAGE() + CHAR(13) + 'Actual Code Line that took the error: ' + CONVERT(nvarchar, ERROR_LINE())
                                               + CHAR(13) + 'Actual Proc that took the error: ' + CONVERT(nvarchar(126), ERROR_PROCEDURE())
             ,@ErrorSeverity = ERROR_SEVERITY()
             ,@ErrorState    = ERROR_STATE()
             ,@ErrorNumber   = ERROR_NUMBER();

    IF( @TranStarted = 1 AND (XACT_STATE()) = -1 ) BEGIN  SET @TranStarted = 0; ROLLBACK TRANSACTION; END
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
    END CATCH
    -- ======================================================================================
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文