2

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

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

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

我在互联网上搜索过,只找到了一些帖子,但据我所知,这应该可行。我正在使用 SQL Server 2008 R2。

我已将代码简化为以下内容:主代码打开一个主事务,然后并行运行 2 个线程,每个线程使用一个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

4

0 回答 0