因為要做一個號碼歸屬地查詢小功能,因為要導入外部(文本文件)的電話歸屬地數據,使用的是SqlDataAdapter類,數據不多,只四萬有多條,表也只有一個,phoneBook表,使用的是DataTable和SqlDataAdapter,測試了三次導入,平均18秒,但是我覺得太慢了,就百度了下【SQL Server批量導入數據】,發現了SqlBulkCopy這個神器,一秒內導入。
SqlBulkCopy 這個類用於數據庫大批量的數據傳遞,通常用於新舊數據庫之間的更新。關鍵的一點是,即使表結構不同,也可以通過表字段或者字段位置建立映射關系,將所需的數據導入到目標數據庫。
下面代碼測試了數據量為一百萬條數據,幾次測試耗時8秒左右。
/// <summary> /// SqlBulkCopy類的使用,批量更新數據 /// </summary> public static void SqlBulkCopyDemo() { String connStr = ConfigurationManager.ConnectionStrings["connStr"].ToString(); //從數據庫中獲得表結構和數據 DataTable student = new DataTable(); SqlDataAdapter adapter = new SqlDataAdapter("select * from student", connStr); adapter.Fill(student); //向表中添加數據 DataRow dr; Random r = new Random(); Stopwatch st = new Stopwatch(); for(int i = 0; i<1000000; i++)//一百萬條數據 {//數據表中的列:name,no,age,sex dr = student.NewRow(); dr[0] = "小花" + i; dr[1] = 108 + i; dr[2] = r.Next(9, 40);//這里是因為數據表中有約束, dr[3] = (i % 2 == 0 ? "男" : "女");//這個也是有約束 student.Rows.Add(dr); } SqlBulkCopy bulk = new SqlBulkCopy(connStr); bulk.DestinationTableName = "student";//設置目標表,這里是數據庫中的student表 bulk.ColumnMappings.Add(0, 0);//建立映射關系 bulk.ColumnMappings.Add(1, 1); bulk.ColumnMappings.Add(2, 2); bulk.ColumnMappings.Add(3, 3); st.Start();//開始計時 bulk.WriteToServer(student.GetChanges()); st.Stop();//結束計時 Console.WriteLine("數據插入成功,耗時為:" + st.ElapsedMilliseconds + "毫秒"); }
測試了三次,結果如下:
1、SqlBulkCopy類的構造方法
其中: conn表示一個SqlConnection對象
connStr表示數據庫連接字符串
- SqlBulkCopy(conn)
- SqlBulkCopy(connStr)
- SqlBulkCopy(connStr, SqlBulkCopyOptions copyOptions)
- SqlBulkCopy(conn, SqlBulkCopyOptions copyOptions, SqlTransaction externalTransaction)
其中還有幾個陌生的對象:SqlBulkCopyOptions 和 SqlTransaction
1.1、SqlBulkCopyOptions類
這個類是一個枚舉類型:
| 對象 | 值 | 備注 |
| Default | 0 | |
| KeepIdentity | 1 | 保留源標識值。 如果未指定,則由目標分配標識值。 |
| CheckConstraints | 2 | 在插入數據的同時檢查約束。 默認情況下,不檢查約束。 |
| TableLock | 4 | 在批量復制操作期間獲取批量更新鎖。 如果未指定,則使用行鎖。 |
| KeepNulls | 8 | 保留目標表中的空值,而不管默認值的設置如何。 如果未指定,則空值將由默認值替換(如果適用) |
| FireTriggers | 16 | 指定后,會導致服務器為插入到數據庫中的行激發插入觸發器。 |
| UseInternalTransaction | 32 | 如果已指定,則每一批批量復制操作將在事務中進行。 如果指示了此選項,並且為構造函數提供了 System.Data.SqlClient.SqlTransaction對象,則發生 System.ArgumentException(參數異常)。因為兩個事務沖突了。 |
1.2、SqlTransaction類
這個類是事務類,是個密封類,實現了DbTransaction抽象類
2、SqlBulkCopy類的常用屬性
| 屬性名 | 功能 | 備注 |
| BatchSize | 設置或獲取每達到多少行就更新到服務器(也就是目標表) | 值為int, |
| BulkCopyTimeout | 設置或獲取超時時間 | 默認30秒,如果設置成0,將無限制等待, 值為int,單位為秒 |
| DestinationTableName | 設置或獲取服務器上的目標表的名稱 | 也就是批量更新的目標表, 值為String類型 |
| EnableStreaming | 設置或獲取是否支持傳輸 IDataReader 對象的數據 | true為支持, 值為bool類型 |
| NotifyAfter | 設置或獲取在生成通知事件之前要處理的行數 | 默認為0, 值為int類型, |
| ColumnMappings | 獲取列映射定義數據源中的列和目標表中的列之間的映射關系 | 返回值為SqlBulkCopyColumnMappingCollection |
2.1、表中的SqlBulkCopyColumnMappingCollection類型是一個映射集合類,是目標表的列和源表的列的映射關系的集合。
這個類是一個密封類,不能被繼承,實現了一個CollectionBase抽象類。
SqlBulkCopyColumnMappingCollection沒有提供構造方法,我們也不需要去newat的對象,主要是使用它的幾個重載的Add()方法
Add()有五個重載的方法:
- SqlBulkCopyColumnMapping Add(SqlBulkCopyColumnMapping bulkCopyColumnMapping);
- SqlBulkCopyColumnMapping Add(string sourceColumn, string destinationColumn);
- SqlBulkCopyColumnMapping Add(int sourceColumnIndex, string destinationColumn);
- SqlBulkCopyColumnMapping Add(string sourceColumn, int destinationColumnIndex);
- SqlBulkCopyColumnMapping Add(int sourceColumnIndex, int destinationColumnIndex);
其中四個方法是類似的,都是對應的列名或者列的位置。
第一個方法是添加一個已經構建好的SqlBulkCopyColumnMapping對象,
他也有集合常用的方法:
| 方法名 | 功能 | 備注 |
| Clear(); | 清除集合中的映射關系 | |
| Contains(SqlBulkCopyColumnMapping value); | 判斷是否包含指定映射關系 | |
| IndexOf(SqlBulkCopyColumnMapping value); | 返回指定映射關系的位置 | |
| Remove(SqlBulkCopyColumnMapping value); | 移除指定映射關系 | |
| RemoveAt(int index); | 移除指定位置的映射關系 | |
| Insert(int index, SqlBulkCopyColumnMapping value); | 在指定位置插入映射關系 | |
| CopyTo(SqlBulkCopyColumnMapping[] array, int index); | 從指定位置開始將映射關系復制到指定數組中 | index指定的集合中的位置, 而不是數組中的角標 |
3、SqlBulkCopy類的常用方法
- WriteToServer,這個方法重載了四次,功能是將數據寫到目的表中。
| WriteToServer(DataRow[] rows); | 將 DataRow 數組所有元素寫到目標表中 |
| WriteToServer(DataTable table); | 將 DataTable 所有行寫到目標表中 |
| WriteToServer(IDataReader reader); | 將指定的 IDataReader 對象中的數據寫到目標表中 |
| WriteToServer(DataTable table, DataRowState rowState); | 將 DataTable 中指定狀態的所有行寫到目標表中 |
【上表中的 DataRowState 狀態行可以參考這篇博客DataTable的AcceptChanges()方法和DataRow的RowState屬性】
這個類還提供了八個異步寫的方法,我還沒全部理解,就不放上來了。
既然能夠有寫的操作,那這個類應該類似於流,它還有一個Close()方法,用於關閉 SqlBulkCopy 實例。



