使用SqlBulkCopy类进行数据批量复制

在多种不同的场景中,经常需要进行数据的迁移、备份或从不同的数据源收集数据。例如,在将旧系统迁移到新系统的过程中,或者在需要备份数据以防止数据丢失时,都需要进行数据的批量复制。.NET Framework 2.0 提供了一个名为 SqlBulkCopy 的类,它可以帮助将数据从不同的数据源复制到 SQL SERVER 数据库中。本文将展示 SqlBulkCopy 类的不同使用方面。

数据库设计

数据库设计相对简单,它基于 Northwind 数据库中的 Products 表。在 Northwind 数据库中创建了三个额外的表。查看下面的数据库图示,以获得更好的理解。

Products_ArchiveProducts_Latest 表具有与 Products 表相同的模式,而 Products_TopSelling 表则不同。将在本文稍后解释 Products_TopSelling 表的用途。

Products_Archive 表包含 770,000 行数据。不需要担心这些行是如何产生的;只需要考虑如何将所有这些行移动到 Products_Latest 表中。

将数据从 Products_Archive 转移到 Products_Latest

SqlBulkCopy 类包含一个实例方法 WriteToServer,它用于将数据从源传输到目标。WriteToServer 方法可以执行 DataRow[] 数组、DataTableDataReader 的操作。根据情况,可以选择喜欢的容器,但在大多数情况下,选择 DataReader 是一个好主意。这是因为 DataReader 是一个只向前、只读的流。它不持有数据,因此比 DataTableDataRows[] 快得多。下面的代码用于将数据从源表传输到目标表。

private static void PerformBulkCopy() { string connectionString = @" Server=localhost;Database=Northwind;Trusted_Connection=true"; // 获取源数据 using (SqlConnection sourceConnection = new SqlConnection(connectionString)) { SqlCommand myCommand = new SqlCommand("SELECT * FROM Products_Archive", sourceConnection); sourceConnection.Open(); SqlDataReader reader = myCommand.ExecuteReader(); // 打开目标数据 using (SqlConnection destinationConnection = new SqlConnection(connectionString)) { // 打开连接 destinationConnection.Open(); using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnection.ConnectionString)) { bulkCopy.BatchSize = 500; bulkCopy.NotifyAfter = 1000; bulkCopy.SqlRowsCopied += new SqlRowsCopiedEventHandler(bulkCopy_SqlRowsCopied); bulkCopy.DestinationTableName = "Products_Latest"; bulkCopy.WriteToServer(reader); } } reader.Close(); } }

这里有几个要点需要提及。首先,使用 DataReader 从数据库表中获取行。SqlBulkCopy 类对象 "bulkCopy" 设置了 DestinationTableName 属性为目标表,在这个例子中是 "Products_Latest"。Products_Latest 是目标表,因为数据是从 Products_Archive 表传输到 Products_Latest 表。bulkCopy 对象还公开了 SqlRowsCopied 事件,该事件在达到 NotifyAfter 属性标识的行数后触发。这意味着事件将在每 1000 行之后触发,因为 NotifyAfter 设置为 1000。

BatchSize 属性非常重要,因为大部分性能都依赖于它。BatchSize 意味着一次将多少行发送到数据库以启动数据传输。将 BatchSize 设置为 500,这意味着一旦读取器读取了 500 行,它们将被发送到数据库以执行批量复制操作。默认情况下,BatchSize 是 "1",这意味着每一行都作为单个批次发送到数据库。不同的 BatchSize 会给不同的结果。应该测试哪个批次大小适合需求。

在不同映射的表之间传输数据

在上面的例子中,两个表具有相同的模式。有时,需要在模式不同的表之间传输数据。假设想将 Products_Archive 表中的所有产品名称和数量传输到 Products_TopSelling 表中。这两个表的模式是不同的,因为它们具有不同的列名。这在上面的数据库设计部分的图像中也可以看到。

private static void PerformBulkCopyDifferentSchema() { string connectionString = @" Server=localhost;Database=Northwind;Trusted_Connection=true"; DataTable sourceData = new DataTable(); // 获取源数据 using (SqlConnection sourceConnection = new SqlConnection(connectionString)) { SqlCommand myCommand = new SqlCommand("SELECT TOP 5 * FROM Products_Archive", sourceConnection); sourceConnection.Open(); SqlDataReader reader = myCommand.ExecuteReader(); // 打开目标数据 using (SqlConnection destinationConnection = new SqlConnection(connectionString)) { // 打开连接 destinationConnection.Open(); using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnection.ConnectionString)) { bulkCopy.ColumnMappings.Add("ProductID", "ProductID"); bulkCopy.ColumnMappings.Add("ProductName", "Name"); bulkCopy.ColumnMappings.Add("QuantityPerUnit", "Quantity"); bulkCopy.DestinationTableName = "Products_TopSelling"; bulkCopy.WriteToServer(reader); } } reader.Close(); } }

ColumnMappings 集合用于映射源表和目标表之间的列。

从 XML 文件传输数据到数据库表

数据源不仅限于数据库表,还可以使用 XML 文件。这里有一个非常简单的 XML 文件,用作批量复制操作的源。(Products.xml)

<?xml version="1.0" encoding="utf-8"?> <Products> <Product productID="1" productName="Chai"/> <Product productID="2" productName="Football"/> <Product productID="3" productName="Soap"/> <Product productID="4" productName="Green Tea"/> </Products> private static void PerformBulkCopyXMLDataSource() { string connectionString = @" Server=localhost;Database=Northwind;Trusted_Connection=true"; DataSet ds = new DataSet(); DataTable sourceData = new DataTable(); ds.ReadXml(@"C:\Products.xml"); sourceData = ds.Tables[0]; // 打开目标数据 using (SqlConnection destinationConnection = new SqlConnection(connectionString)) { // 打开连接 destinationConnection.Open(); using (SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnection.ConnectionString)) { // 列映射 bulkCopy.ColumnMappings.Add("productID", "ProductID"); bulkCopy.ColumnMappings.Add("productName", "Name"); bulkCopy.DestinationTableName = "Products_TopSelling"; bulkCopy.WriteToServer(sourceData); } } }

文件首先被读取到 DataTable 中,然后被传递给 SqlBulkCopy 类的 WriteToServer 方法。由于目标表是 Products_TopSelling,不得不执行列映射。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485