C# 并行读取SQL Server文件流不工作

C# 并行读取SQL Server文件流不工作,c#,parallel-processing,transactions,sql-server-2008-r2,sqlfilestream,C#,Parallel Processing,Transactions,Sql Server 2008 R2,Sqlfilestream,我试图在并行线程中读取相同的SQL Server文件流,但没有成功 大多数情况下,我会遇到以下异常(尽管有时我会遇到其他错误): System.InvalidOperationException:“进程无法访问指定的文件,因为它已在另一个事务中打开。” 我在互联网上搜索过,只找到了几篇帖子,但据我所知,这应该是可行的。我正在使用SQLServer2008R2 我将代码简化为以下内容:主代码打开一个主事务,然后并行运行两个线程,每个线程使用DependentTransaction,并将SQL Se

我试图在并行线程中读取相同的SQL Server文件流,但没有成功

大多数情况下,我会遇到以下异常(尽管有时我会遇到其他错误):

System.InvalidOperationException:“进程无法访问指定的文件,因为它已在另一个事务中打开。”

我在互联网上搜索过,只找到了几篇帖子,但据我所知,这应该是可行的。我正在使用SQLServer2008R2

我将代码简化为以下内容:主代码打开一个主事务,然后并行运行两个线程,每个线程使用
DependentTransaction
,并将SQL Server文件流复制到磁盘上的临时文件

如果我将threadCount更改为1,则代码可以工作

知道为什么会失败吗

守则:

class Program
{
    private static void Main(string[] args)
    {
        string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
        Directory.CreateDirectory(path);

        try
        {
            using (var transactionScope = new TransactionScope(TransactionScopeOption.Required))
            {
                TransactionInterop.GetTransmitterPropagationToken(Transaction.Current);

                const int threadCount = 2;
                var transaction = Transaction.Current;

                // Create dependent transactions, one for each thread
                var dependentTransactions = Enumerable
                    .Repeat(transaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete), threadCount)
                    .ToList();

                // Copy the file from the DB to a temporary files, in parallel (each thread will use a different temporary file).
                Parallel.For(0, threadCount, i =>
                {
                    using (dependentTransactions[i])
                    {
                        CopyFile(path, dependentTransactions[i]);

                        dependentTransactions[i].Complete();
                    }
                });
                transactionScope.Complete();
            }
        }
        finally
        {
            if (Directory.Exists(path))
                Directory.Delete(path, true);
        }
    }

    private static void CopyFile(string path, DependentTransaction dependentTransaction)
    {
        string tempFilePath = Path.Combine(path, Path.GetRandomFileName());

        // Open a transaction scope for the dependent transaction
        using (var transactionScope = new TransactionScope(dependentTransaction, TransactionScopeAsyncFlowOption.Enabled))
        {
            using (Stream stream = GetStream())
            {
                // Copy the SQL stream to a temporary file
                using (var tempFileStream = File.OpenWrite(tempFilePath))
                    stream.CopyTo(tempFileStream);
            }

            transactionScope.Complete();
        }
    }

    // Gets a SQL file stream from the DB
    private static Stream GetStream()
    {
        var sqlConnection = new SqlConnection("Integrated Security=true;server=(local);initial catalog=DBName");
        var sqlCommand = new SqlCommand {Connection = sqlConnection};

        sqlConnection.Open();
        sqlCommand.CommandText = "SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()";

        Object obj = sqlCommand.ExecuteScalar();
        byte[] txContext = (byte[])obj;

        const string path = "\\\\MyMachineName\\MSSQLSERVER\\v1\\DBName\\dbo\\TableName\\TableName\\FF1444E6-6CD3-4AFF-82BE-9B5FCEB5FC96";
        var sqlFileStream = new SqlFileStream(path, txContext, FileAccess.Read, FileOptions.SequentialScan, 0);

        return sqlFileStream;
    }
}

kk

交易范围
与依赖交易是一种奇特的内裤。考虑破解一个SQL分析器,看看它在引擎盖上做了什么,在<代码>开始事务>代码> />代码>提交/代码>和会话。或者,如果您不需要它提供的高层次抽象,请考虑使用显式事务(如,在代码>连接。即使你真的需要它,也值得尝试一下,看看什么能起作用。一个连接只能执行一个命令,并行与否,跨连接的事务充满了危险。感谢您的快速回复。我需要整个代码是事务性的和并行的。我简化了我的原始代码,它以可回滚的方式处理文件,而不是复制到临时文件。如果我错了,请纠正我,但如果我使用BeginTransaction,它将为每个线程创建单独的事务,因此如果其中一个线程失败,其他线程将不会回滚。此外,在代码中,每个线程都打开一个连接并运行一个命令。我的评论的核心是:无论客户端代码做什么,一个物理SQL Server连接一次都不能处理多个命令(不包括MARS之类的伪并行性),并且任何事务都不能跨物理连接,除非是分布式的。SQL Server根本不关心线程的排列方式,但如果两个线程同时运行一个命令,它们必须使用不同的物理连接(而不是像正常情况那样仅重用相同的池连接)。这意味着,为了让你想要的成为可能,.NET代码必须做一些有趣的事情……而我不知道这些是什么有趣的事情。所以在我忘记之前,请投票表决。我目前没有时间深入研究这种情况。实际上,在我的例子中,它实际上是一个分布式事务,在原始代码中,每个线程实际上都会将文件复制到不同机器上的数据库(通过WCF操作),这就是为什么我需要它同时具有事务性和并行性。无论如何,如果这段代码是错误的,那么实现我所需要的(即并行和事务性地执行多文件复制)的正确方法是什么?