簡體   English   中英

SQL連接在SqlBulkCopy期間關閉

[英]SQL connection closes during SqlBulkCopy

我正在嘗試使用SqlBulkCopy將數據導入到臨時表中。

private bool CreateTempTable(IDbConnection conn, byte[] fileByteArray, string tempTableName)
{
        try
        {
            Stream stream = new MemoryStream(fileByteArray);

            using (var reader = new CsvReader(stream, false, System.Text.Encoding.UTF8))
            {
                // Bulk insert the data into a temporary table.
                using (SqlBulkCopy bulkCopy = new SqlBulkCopy((SqlConnection)conn))
                {
                    // Import the data into the temp table
                    bulkCopy.DestinationTableName = tempTableName;
                    bulkCopy.EnableStreaming = true;
                    bulkCopy.BatchSize = 20000;
                    bulkCopy.BulkCopyTimeout = 600;
                    bulkCopy.WriteToServer(reader);
                }
            }
        }
        catch (Exception ex)
        {
            Logger.Error(ex, $"CreateTempTable(): Exception while creating the TempTable \"{tempTableName}\" - {ex.Message}");
            return false;
        }

        return true;
}

在另一個異步運行的方法中調用此方法。 連接是通過類似於以下代碼的代碼傳遞和維護的:

private async Task<bool> ConsumeAsyn(byte[] fileByteArray, string tempTableName)
{
        using (var conn = (SqlConnection)OpenConnection())
        {
            if (CreateTempTable(conn, fileByteArray, tempTableName))
            {
                // success
            }
            else
            {
                // fail
            }
        }
}

基本上,這就是ConsumeAsync的調用方式:

    public async Task<bool> ProcessNextAsync2()
    {
        try
        {
            isIdle = false;

            string filePath = ImportFilePickupPath + "\\" + Filename;
            byte[] inStream = await LoadImportFileAsync(filePath);

            bool consumeSuccess = await Consume(inStream, "##TempTable");

            if (consumeSuccess)
            {
                // Delete the file
                DeleteImportFile(filePath);
            }
            else
            {
                // Rescedule job
            }

            isIdle = true;
        }
        catch (Exception ex)
        {
            isIdle = true;
        }

        return isIdle;
    }

如果我在csv中使用大約100行的小型記錄集,則一切正常。 問題是如果我有成千上萬的記錄,則在批量導入過程中連接將終止。

如何將連接傳遞給方法,並確保在批量導入完成之前它保持打開狀態?

也許是一個答案,也許不是,但是可能需要將IDisposables(至少/尤其是SqlConnection)保留在異步任務之外。

這個答案似乎使.NET認為IDiposables不在范圍內,因此在您仍嘗試使用它們時將其處置:

SqlBulkCopy.WriteToServer()不斷獲取“連接已關閉”

我可以通過刪除對第三方nuget lib的支持來解決我的問題,該第三方nuget lib刪除了我的連接。 盡管尚不清楚它為什么會發生,但擺脫所有異步調用並自己管理連接似乎已解決了我的問題。 批量導入工作正常,但是處理## Temp表中的數據很慢。 我決定將所有內容保留在內存中並從那里進行處理。

    private bool Consume(byte[] fileByteArray, IDataProcess dataConsumer)
    {
        try
        {
            using (var conn = OpenConnection())
            {
                // Convert byte Array to a stream
                Stream stream = new MemoryStream(fileByteArray);

                // Create a reader from the stream
                using (var reader = new CsvReader(stream, false, System.Text.Encoding.UTF8))
                {
                    RecordEnumerator enumerator = reader.GetEnumerator();
                    enumerator.MoveNext();
                    do
                    {
                        // Proccess enumerator.Current with dataConsumer

                    } while (enumerator.MoveNext());
                }
            }
        }
        catch (Exception ex)
        {
            return false;
        }
        return true;
    }

我們冒着內存不足的風險,但是在我們找到更快的方法之前,必須這樣做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM