批量插入数据利器之SqlBulkCopy
工作中要频繁的处理一些数据导入,又不想手工去做,因此用了神器SqlBulkCopy。在MSDN查看了此类的帮助文档几经波折终于搞定,记录下来方便以后查阅。
MSDN实例:
1 using System.Data.SqlClient; 2 3 class Program 4 { 5 static void Main() 6 { 7 string connectionString = GetConnectionString(); 8 // Open a sourceConnection to the AdventureWorks database. 9 using (SqlConnection sourceConnection = 10 new SqlConnection(connectionString)) 11 { 12 sourceConnection.Open(); 13 14 // Perform an initial count on the destination table. 15 SqlCommand commandRowCount = new SqlCommand( 16 "SELECT COUNT(*) FROM " + 17 "dbo.BulkCopyDemoMatchingColumns;", 18 sourceConnection); 19 long countStart = System.Convert.ToInt32( 20 commandRowCount.ExecuteScalar()); 21 Console.WriteLine("Starting row count = {0}", countStart); 22 23 // Get data from the source table as a SqlDataReader. 24 SqlCommand commandSourceData = new SqlCommand( 25 "SELECT ProductID, Name, " + 26 "ProductNumber " + 27 "FROM Production.Product;", sourceConnection); 28 SqlDataReader reader = 29 commandSourceData.ExecuteReader(); 30 31 // Open the destination connection. In the real world you would 32 // not use SqlBulkCopy to move data from one table to the other 33 // in the same database. This is for demonstration purposes only. 34 using (SqlConnection destinationConnection = 35 new SqlConnection(connectionString)) 36 { 37 destinationConnection.Open(); 38 39 // Set up the bulk copy object. 40 // Note that the column positions in the source 41 // data reader match the column positions in 42 // the destination table so there is no need to 43 // map columns. 44 using (SqlBulkCopy bulkCopy = 45 new SqlBulkCopy(destinationConnection)) 46 { 47 bulkCopy.DestinationTableName = 48 "dbo.BulkCopyDemoMatchingColumns"; 49 50 try 51 { 52 // Write from the source to the destination. 53 bulkCopy.WriteToServer(reader); 54 } 55 catch (Exception ex) 56 { 57 Console.WriteLine(ex.Message); 58 } 59 finally 60 { 61 // Close the SqlDataReader. The SqlBulkCopy 62 // object is automatically closed at the end 63 // of the using block. 64 reader.Close(); 65 } 66 } 67 68 // Perform a final count on the destination 69 // table to see how many rows were added. 70 long countEnd = System.Convert.ToInt32( 71 commandRowCount.ExecuteScalar()); 72 Console.WriteLine("Ending row count = {0}", countEnd); 73 Console.WriteLine("{0} rows were added.", countEnd - countStart); 74 Console.WriteLine("Press Enter to finish."); 75 Console.ReadLine(); 76 } 77 } 78 } 79 80 private static string GetConnectionString() 81 // To avoid storing the sourceConnection string in your code, 82 // you can retrieve it from a configuration file. 83 { 84 return "Data Source=(local); " + 85 " Integrated Security=true;" + 86 "Initial Catalog=AdventureWorks;"; 87 } 88 }
MSDN 地址:https://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqlbulkcopy(v=vs.110).aspx
自己的测试代码:
1 /// <summary> 2 /// 将DataTable表数据插入数据库目标表 3 /// DataTable Name 和数据库目标表名称一致,DataTable列名为目标数据库目标表字段 4 /// </summary> 5 /// <param name="dt">数据源</param> 6 /// <param name="dbFlag">数据库标识</param> 7 /// <returns></returns> 8 public static bool MassInsert(DataTable dt, string dbFlag) 9 { 10 if (dt == null || dt.Rows.Count == 0) 11 { 12 Logger.Write("DataTable为空或无填充行", "大数据操作", ""); 13 return false; 14 } 15 if (String.IsNullOrEmpty(dt.TableName)) 16 { 17 Logger.Write("DataTableName为空无法确定目标数据库表", "大数据操作", ""); 18 return false; 19 } 20 SqlConnection con = HelpGetSqlCon(dbFlag);//动态获取SqlConnection对象 21 DateTime time = DateTime.Now; 22 SqlTransaction tra = con.BeginTransaction();//事务 23 SqlBulkCopy sqlBC = new SqlBulkCopy(con, SqlBulkCopyOptions.Default, tra); 24 try 25 { 26 sqlBC.DestinationTableName = dt.TableName; 27 //一次批量的插入的数据量 28 sqlBC.BatchSize = dt.Rows.Count; 29 sqlBC.WriteToServer(dt); 30 Logger.Write("【MassInsert】[" + dt.Rows.Count + "]条数据共耗时[" + (DateTime.Now - time).TotalSeconds.ToString() + "]秒", "", ""); //记录日志 31 tra.Commit(); 32 return true; 33 } 34 catch (Exception ex) 35 { 36 tra.Rollback(); 37 Logger.WriteException("MassInsert异常", "", ex, ""); 38 return false; 39 } 40 finally 41 { 42 dt.Clear(); 43 dt.Dispose(); 44 sqlBC.Close(); 45 con.Dispose(); 46 con.Close(); 47 } 48 }
以上代码可以插入主键,如果主键重复则事务回滚
正常测试结果:
【2015-04-29 12:49:44】
【MassInsert】[182689]条数据共耗时[3.4911996]秒
主键重复测试结果:
【2015-04-29 12:41:16】
Message:MassInsert异常
Ex.Message:违反了 PRIMARY KEY 约束“PK_AUTHCODES”。不能在对象“dbo.AuthCodes”中插入重复键。重复键值为 (1)。
语句已终止。
Ex.StackTrace: 在 System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
在 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
在 System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
在 System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
在 System.Data.SqlClient.SqlBulkCopy.RunParser(BulkCopySimpleResultSet bulkCopyHandler)
在 System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsyncContinuedOnSuccess(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource`1 source)
在 System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsyncContinued(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource`1 source)
在 System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsync(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource`1 source)
在 System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalRestContinuedAsync(BulkCopySimpleResultSet internalResults, CancellationToken cts, TaskCompletionSource`1 source)
在 System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalRestAsync(CancellationToken cts, TaskCompletionSource`1 source)
在 System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalAsync(CancellationToken ctoken)
在 System.Data.SqlClient.SqlBulkCopy.WriteRowSourceToServerAsync(Int32 columnCount, CancellationToken ctoken)
在 System.Data.SqlClient.SqlBulkCopy.WriteToServer(DataTable table, DataRowState rowState)
在 System.Data.SqlClient.SqlBulkCopy.WriteToServer(DataTable table)