是否可以将 System.Transactions.TransactionScope 与 SqlBulkCopy 一起使用?

发布于 2024-12-03 05:34:17 字数 242 浏览 5 评论 0原文

非常简单的问题:是否可以将 System.Transactions.TransactionScope 与 SqlBulkCopy 一起使用?文档事务和批量复制操作没有提及任何内容(至少从 .NET 4.0 开始),并且我的测试表明它不会自动加入 TransactionScope

Very simple question: is it possible to use System.Transactions.TransactionScope together with SqlBulkCopy? The documentation Transaction and Bulk Copy Operations doesn't mention anything (at least as of .NET 4.0) and my testing indicates it does not automatically enlist with TransactionScope.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

童话 2024-12-10 05:34:18

SqlBulkCopy 从不登记到事务中。 SqlCommand 也不会这样做。常见的误解。登记是在调用 SqlConnection.Open 时执行的。之后,在该连接上运行的任何内容都是隐式事务的一部分。事实上,不再允许传递显式交易。

如果您希望 SqlBulkCopy 使用 TransactionScope 参与 System.Transactions.Transaction,则必须在打开连接时设置事务。

这很容易做到:

using (var tran = new TransactionScope(...))
using (var conn = new SqlConnection(connStr))
{
  conn.Open(); //This enlists.

  using (var sqlBulkCopy = new SqlBulkCopy(conn)) {
    sqlBulkCopy.WriteToServer(...);
  }

  tran.Complete(); //Commit.
}

您只需要这段代码即可。可能的错误:

  1. 交易必须尽早开启。
  2. 请勿使用 SqlBulkCopySqlTransaction 参数。传递null
  3. 不要使用SqlBulkCopyOptions.UseInternalTransaction
  4. 除非您想实际做某事,否则不要添加异常处理。如果没有提交,回滚是自动的。
  5. 使用 using 语句进行干净的代码和确定性清理。除非必要,否则请勿手动关闭或处置任何这些物体。这将是多余的。

您可以使用任何您喜欢的批量大小,并且所有批量都将成为交易的一部分。因此,批处理的价值有限(特别是事务日志不能提前截断)。首先尝试完全不进行批处理。

SqlBulkCopy never enlists into a transaction. SqlCommand also does not do that. Common misconception. The enlistment is performed at the time SqlConnection.Open is called. After that, anything that runs on that connection is part of the transaction implicitly. In fact it is no longer allowed to pass an explicit transaction.

If you want SqlBulkCopy to take part in a System.Transactions.Transaction using TransactionScope the transaction must be set at the time you open the connection.

It is very easy to do:

using (var tran = new TransactionScope(...))
using (var conn = new SqlConnection(connStr))
{
  conn.Open(); //This enlists.

  using (var sqlBulkCopy = new SqlBulkCopy(conn)) {
    sqlBulkCopy.WriteToServer(...);
  }

  tran.Complete(); //Commit.
}

This code is all you need. Possible mistakes:

  1. The transaction must be opened early enough.
  2. Do not use the SqlTransaction parameter of SqlBulkCopy. Pass null.
  3. Do not use SqlBulkCopyOptions.UseInternalTransaction.
  4. Do not add exception handling unless you want to actually do something. Rollback is automatic if there is no commit.
  5. Use the using statement for clean code and deterministic cleanup. Do not manually close or dispose any of these objects unless you have to. This would be redundant.

You can use any batch size you like and all batches will be part of the transaction. Therefore, batching has limited value (in particular the transaction log cannot be truncated early). Try no batching at all first.

樱娆 2024-12-10 05:34:18

要执行跨所有批次(并且可选地跨其他数据库语句)的原子 SqlBulkCopy 导入,我们需要使用事务。以下步骤概述了通过 SqlBulkCopy 使用事务的过程:

  1. 创建到目标数据库服务器的 SqlConnection。
  2. 打开连接。
  3. 创建一个 SqlTransaction 对象。
  4. 创建传入SqlTransaction对象的SqlBulkCopy对象
    进入构造函数。
  5. 执行导入 - 调用 WriteToServer - 在
    尝试...抓住块。
    如果操作完成,则提交事务;如果失败,则回滚。

通过 SqlBulkCopy 使用事务

To perform atomic SqlBulkCopy imports that span across all batches (and, optionally, across other database statements) we need to use transactions. The following steps outline the process of using a transaction with SqlBulkCopy:

  1. Create a SqlConnection to the destination database server.
  2. Open the connection.
  3. Create a SqlTransaction object.
  4. Create the SqlBulkCopy object passing in the SqlTransaction object
    into the constructor.
  5. Perform the import - the call to WriteToServer - within a
    Try...Catch block.
    If the operation completes, commit the transaction; if it fails, roll it back.

Using Transactions with SqlBulkCopy

孤千羽 2024-12-10 05:34:18

(据我所知)在批量加载中定义事务的唯一方法是指定批量大小。

批量加载的优点是可以获得批量更新锁(多线程读取和多线程写入)。当使用 bcp、批量插入、带有 (tablock) 的 ssis 数据流任务、insert(columns)select columns from openrowset (bulk) 或 sqlbulkcopy 时,您会得到此信息。当尝试最小化加载时间和事务日志大小时,这非常方便(仅当您满足最小日志记录要求时,这将为您节省数百万行的时间)。

每当加载数据时,事务日志都将成为瓶颈。如果时间至关重要,那么尽量减少记录的数量就很重要。

一旦满足批量大小(您指定提交的行数),事务就会提交并重新开始。如果指定批量大小为 0,则事务将覆盖整个文件,并在出现任何数据问题时回滚。

The only way to define the transaction in a bulk load (to my knowledge) is to specify the batchsize.

The advantage of the bulk load is that you get a bulk update lock (multi-threaded read and a multi-threaded write). You get this when using bcp, bulk insert, a ssis data flow task with (tablock), a insert(columns)select columns from openrowset (bulk), or a sqlbulkcopy. This is handy when trying to minimize both the time to load and the transaction log size (only if you have satisfied the minimally logged requirements, which will save you hours on millions of rows).

Anytime you load data, the transaction log is going to be the bottleneck. If time is of the essence, it's important to minimize how much gets logged.

Once the batchsize is satisfied (the number of rows that you specified to commit on) the transaction gets committed and starts over. If you specify a batchsize of 0, the transaction will cover the entire file and rollback if any data issues arise.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文