1

我在将大量记录插入 Sql 服务器表时遇到问题。我通过使用 SqlBulkCopy 解决了这个问题。现在我能够很快地插入记录。

我有疑问,如果在插入记录时任何事务失败,我必须重试相同的操作 3 次。我们如何使用 SqlBulkCopy 实现重试逻辑?

using (var connection = DatabaseOperations.CreateConnection(ConnectString))
    {
        connection.Open();
        var transaction = connection.BeginTransaction();
        try
        {
            var dt = new DataTable();
            dt.Columns.Add("EmployeeID");
            dt.Columns.Add("Name"); 
            for (var i = 1; i < 1000000; i++)    
                dt.Rows.Add(i + 1, "Name " + i + 1);

            using (var sqlBulk = new SqlBulkCopy(connection,SqlBulkCopyOptions.Default, transaction as SqlTransaction))
            {
                sqlBulk.DestinationTableName = "Employees";
                sqlBulk.BatchSize = 100000;
                sqlBulk.WriteToServer(dt);
            }
        }
        catch (SqlException ex)
        {
            transaction.Rollback();
            throw new CustomException("SQL Exception", ex);
        }
        catch (Exception e)
        {
            transaction.Rollback();
            throw;
        }
        transaction.Commit();
    }
4

1 回答 1

0

这里有一个提示:不要将 SqlBulkCopy 复制到目标表中。就这么简单。

我花了一天时间来解决这个问题。

  • 获取目标表的模式(使用 INFORMATION_SCHEMA 很简单)
  • 生成具有相同字段的临时表。
  • 插入临时表
  • 然后使用 INSERT INTO SELECT FROM 复制数据。

整个 SqlBulkCopy 锁定机制已无法修复。它获得一个独占表锁。它可能不需要,但没关系。

问题是:它试图在不等待的情况下获得一个 - 任何行块上的任何锁。它重试 X 次,然后放弃。在繁忙的桌子上,这永远不会(或很少)起作用。

哦,它在上传过程中保持锁定,这通常比我的解决方案插入慢。

我的方法解决了这个问题。您始终可以在自己的临时表上获得表锁。然后插入等待排队。而且复制速度比网络上传快。

哦,你不需要 DataTable - 你可以很容易地使用反射来编写你自己的对象表源(几个小时)。DataTable 是一个内存猪。

于 2021-11-03T12:15:00.523 回答