繁体   English   中英

跨流程使用事务

[英]Using transactions across processes

我正在尝试使用System.Transactions(TransactionScope)来协调一组进程,每个进程都完成一些数据库工作。 最终,所有进程都需要通过一个父进程来提交或自动回滚。 不幸的是,到目前为止,我没有尝试过任何方法。

我的基本策略是在父进程中使用TransactionScope,将其保存到文件中,然后调用子进程,该子进程加载文件,在其自己的TransactionScope中使用事务,然后返回到父进程。

但这对我不起作用。 当我从给第一个孩子打电话回来时,有时会看到父事务已被标记为异常终止。 尝试克隆它会引发TransactionAbortedException。

当第二个孩子尝试反序列化事务时,我也看到了异常,我得到了代码为0x8004d00e的TransactionException。

我正在尝试执行跨AppDomain和流程的TransactionScopehttp://blogs.microsoft.co.il/blogs/sasha/archive/2010/04/30/propagating-a-transaction-across-appdomains中描述的操作。 aspx 无论如何,没有运气。

这是我尝试过的一些尝试,但没有成功:

  1. 通过加载的事务在子进程中通过DependentClone()创建DependentTransaction
  2. 在将事务保存到文件之前,通过父进程中的DependentClone()创建DependentTransaction
  3. 在将事务保存到文件之前,在父进程中创建Clone()
  4. 使用序列化保存事务
  5. 使用TransactionInterop.GetTransactionFromTransmitterPropagationToken()保存事务
  6. 在父级的TransactionScope之前显式打开连接
  7. 明确要求交易在父公司内部
  8. 明确征求孩子内部的交易
  9. 完成/未完成父范围
  10. 完成/未完成子范围
  11. 在父级中明确创建一个CommittableTransaction

这是一条异常消息:

System.Transactions.TransactionException:该事务已被隐式或显式提交或中止。 ---> System.Runtime.InteropServices.COMException:事务已被隐式或显式提交或中止(来自HRESULT的异常:0x8004D00E)

另一个(使用DependentClone()时):

System.Transactions.TransactionAbortedException:事务已中止。 在System.Transactions.DependentTransaction..ctor(在System.Transactions.DependentTransaction..ctor(在IsolationLevel isoLevel,在ternalTransaction internalTransaction,布尔型阻塞)在System.Transactions.Transaction.DependentClone(DependentCloneOption cloneO ption)

有什么想法我做错了吗? 我尝试了很多这种排列,但没有任何运气。

这是一些代码(它不会尝试演示上述所有变体):

        // one variant I have tried is to create a CommittableTransaction
        // and pass that in the scope below

        using (TransactionScope scope = new TransactionScope())
        {
            // optionally, do some parent-level EF work

            // invoke child operations in other processes
            DoChildOperation_OutOfProc(1, Transaction.Current);
            DoChildOperation_OutOfProc(2, Transaction.Current);

            scope.Complete();
        }

        // in the variant where I created a CommittableTransaction,
        // I committed it here

    ...

    private static void DoChildOperation_OutOfProc(int id, Transaction transaction)
    {
        string tranFile = string.Format("ChildTran_{0}.txt", id);
        SaveTransactionToFile(transaction, tranFile);

        Process process = new Process();
        process.StartInfo = new ProcessStartInfo(Process.GetCurrentProcess().MainModule.FileName.Replace(".vshost", string.Empty),
            string.Format("-CHILDID={0} -TRANFILE={1}", id, tranFile));
        process.StartInfo.UseShellExecute = false;
        process.Start();
        process.WaitForExit();
    }

    private static void SaveTransactionToFile(Transaction transaction, string tranFile)
    {
        byte[] transactionBytes =
            TransactionInterop.GetTransmitterPropagationToken(transaction);

        string tranFileContents = Convert.ToBase64String(transactionBytes);

        File.WriteAllText(tranFile, tranFileContents);
    }

    private static Transaction LoadTransactionFromFile(string tranFile)
    {
        string tranFileContents = File.ReadAllText(tranFile);
        File.Delete(tranFile);

        byte[] tranBytes = Convert.FromBase64String(tranFileContents);

        Transaction tran = 
            TransactionInterop.GetTransactionFromTransmitterPropagationToken(tranBytes);
        return tran;
    }

    // the child instance of the app runs this after decoding the arguments
    // from DoChildOperation_OutOfProc() and loading the transaction out of the file

    private static void DoChildOperation(int id, Transaction childTransaction)
    {
        // in one variant, I call 
        // childTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete)
        // and then use that inside the TransactionScope

        using (TransactionScope scope = new TransactionScope(childTransaction))
        {
            // do EF work and call SaveChanges()

            scope.Complete();
        }

        // if I created a dependent clone, call Complete() here on it

好的,关键似乎是可以在父级中使用TransactionScope,但不能在子级中使用。 对于孩子,我打开EF连接,并通过传递的事务调用connection.EnlistTransaction(),并执行EF SaveChanges()或transaction.Rollback()但不提交(Transaction类不提供此功能)。 这样,看来我得到了想要的行为。

在我的理解中,差距实际上是事务是否被嵌套(就像您在SQL Server中那样)。 看来事实并非如此。 这是同一笔交易。 注意:即使您在子级中使用Transaction.DependentClone()创建DependentTransaction,将其放入TransactionScope仍然会失败。

事实证明这有点不幸,因为这意味着如果您的流程是父流程,则可以使用TransactionScope,但是如果它是子流程,则不能。

暂无
暂无

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

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