web-dev-qa-db-ja.com

SqlBulkCopyは自動的にトランザクションを開始しますか?

私はSqlBulkCopyを介して次のようにデータを挿入しています:

public void testBulkInsert(string connection, string table, DataTable dt)
{
    using (SqlConnection con = new SqlConnection(connection))
    {
        con.Open();

        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(con))
        {
            bulkCopy.DestinationTableName = table;
            bulkCopy.WriteToServer(dt);
        }
    }
}

これは自動的にSQLトランザクションでラップされるので、DBの途中で問題が発生した場合、一括挿入が開始される前と同じ状態のままになりますか?または半分のデータが挿入されますか?

つまり、con.BeginTransactionを明示的に呼び出す必要がありますか

または、文字列を受け取るSqlBulkCopyのコンストラクターを呼び出す場合、それはトランザクションで発生させるためのより良い方法ですか?

public void testBulkInsert(string connection, string table, DataTable dt)
{
    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
    {
        bulkCopy.DestinationTableName = table;
        bulkCopy.WriteToServer(dt);
    }
}

私は docs が最初にこう述べているので、この問題については少し不明確です

デフォルトでは、一括コピー操作は分離された操作として実行されます。一括コピー操作は非トランザクション方式で行われ、ロールバックする機会はありません

しかし、その後の状態

デフォルトでは、一括コピー操作は独自のトランザクションです。専用の一括コピー操作を実行する場合は、接続文字列を使用してSqlBulkCopyの新しいインスタンスを作成するか、アクティブなトランザクションなしで既存のSqlConnectionオブジェクトを使用します。各シナリオで、一括コピー操作はトランザクションを作成し、次にコミットまたはロールバックします。

だからする必要があります:

public void testBulkInsert(string connection, string table, DataTable dt)
{
    using (SqlConnection con = new SqlConnection(connection))
    {
        con.Open();
        using (SqlTransaction tr = con.BeginTransaction(IsolationLevel.Serializable))
        {
            using (SqlBulkCopy bulkCopy = new SqlBulkCopy(con, SqlBulkCopyOptions.Default, tr))
            {
                bulkCopy.DestinationTableName = table;
                bulkCopy.WriteToServer(dt);
            }
            tr.Commit();
        }
    }
}
19
Dan

msdnSqlBulkCopyドキュメントからのテキストはありません

デフォルトでは、一括コピー操作は分離された操作として実行されます。 一括コピー操作は非トランザクション方式で行われ、ロールバックする機会はありません。エラーが発生したときに一括コピーの全部または一部をロールバックする必要がある場合は、SqlBulkCopy管理のトランザクションを使用するか、既存のトランザクション内で一括コピー操作を実行するか、またはSystem.Transactionsトランザクション。

EDIT:私があなたに与えたリンクから、ドキュメントを適切に読みます:

デフォルトでは、一括コピー操作は独自のトランザクションです。専用の一括コピー操作を実行する場合は、接続文字列を使用してSqlBulkCopyの新しいインスタンスを作成するか、
アクティブなトランザクションのない既存のSqlConnectionオブジェクト。各シナリオでは、一括コピー操作によってトランザクションが作成され、トランザクションがコミットまたはロールバックされます。

これは、ケースの内部一括コピートランザクション用に記述されており、デフォルトではありませんデフォルトです!

   using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
                       connectionString, SqlBulkCopyOptions.KeepIdentity |
                       SqlBulkCopyOptions.UseInternalTransaction))
   {
       ....
   }

SqlBulkCopyOptions.UseInternalTransactionをよく見てください。 SqlBulkCopyクラスコンストラクターでUseInternalTransactionオプションを明示的に指定して、一括コピー操作を独自のトランザクションで明示的に実行させ、一括コピー操作の各バッチを個別のトランザクション内で実行させます。異なるバッチが異なるトランザクションで実行されるため、一括コピー操作中にエラーが発生した場合、現在のバッチのすべての行はロールバックされますが、以前のバッチの行はデータベースに残ります。


エラーが発生したために一括コピー操作全体をロールバックする必要がある場合、または一括コピーをロールバックできるより大きなプロセスの一部として実行する必要がある場合は、SqlTransactionオブジェクトを提供できますSqlBulkCopyコンストラクターへ。

外部取引ケース。

            using (SqlTransaction transaction =
                       destinationConnection.BeginTransaction())
            {
                using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
                           destinationConnection, SqlBulkCopyOptions.KeepIdentity,
                           transaction))
                {
                     ....
                }
            }

私が最初の答えはノーだと言ったように、既存のトランザクションまたは内部一括コピートランザクションを使用する必要があります。詳細については、リンクにあるドキュメントファイルを参照してください。

トランザクションが必要な場合は、私が書いた2つのケースのいずれかを使用する必要があります。

39
mybirthname