使用System.Transactions.TransactionScope与SqlBulkCopy是否可能?

38
一个非常简单的问题:是否可以将 System.Transactions.TransactionScopeSqlBulkCopy 结合使用?文档 Transaction and Bulk Copy Operations 没有提到任何信息(至少在 .NET 4.0 中),而我的测试表明它不会自动使用 TransactionScope

以下是关于TransactionScope的一些答案,可能对您的情况有所帮助:https://dev59.com/qXE85IYBdhLWcg3wNwx3 - Only You
3个回答

55

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 语句使代码清晰且具有确定性清理。除非必须,否则不要手动关闭或处置这些对象。这将是冗余的。

你可以使用任何批量大小,所有批次都将成为事务的一部分。因此,批处理具有有限的价值(特别是无法提前截断事务日志)。首先尝试不进行任何批处理。


4
为了执行跨越所有批次(以及可选地跨越其他数据库语句)的原子SqlBulkCopy导入,我们需要使用事务。以下步骤概述了使用SqlBulkCopy事务的过程:
  1. 创建到目标数据库服务器的SqlConnection。
  2. 打开连接。
  3. 创建SqlTransaction对象。
  4. 创建SqlBulkCopy对象并将SqlTransaction对象传递给构造函数。
  5. 在Try...Catch块内执行导入 - 调用WriteToServer。 如果操作完成,则提交事务;如果失败,则回滚事务。
使用SqlBulkCopy事务

如果涉及到两个数据库怎么办? - Saeed Neamati
5
此回答未说明被询问的TransactionScope。 - usr

3
据我所知,唯一定义批量加载中的事务的方式是指定批处理大小。
批量加载的优点在于您可以获得批量更新锁(多线程读取和多线程写入)。当使用bcp、批量插入、带有(tablock)的ssis数据流任务、insert(columns)select columns from openrowset(bulk)或sqlbulkcopy时,您会获得这个锁。当尝试将加载时间和事务日志大小最小化时(仅在满足最小记录要求的情况下),这非常方便(这将为您节省数百万行的时间)。
每次加载数据时,事务日志都将成为瓶颈。如果时间很重要,则需要尽量减少记录的数量。
一旦满足了批处理大小(您指定要提交的行数),事务就会提交并重新开始。如果指定批处理大小为0,则事务将覆盖整个文件,并在出现任何数据问题时回滚。

很不幸。我需要将单行提交和批量加载到多个表中,然后在另一个表中进行单行更新,这些操作必须全部成功或全部失败。我希望能够轻松地通过将提交、批量加载和最终更新包装在一个“TransactionScope”中来完成。我只能采取不同的方法了。感谢您详细的答案,非常感谢。 - jason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接