在SQL Server中使用SQLBulkCopy批量插入數據

在.Net1.1中不管是對於批量插入整個DataTable中的全部數據到數據庫中,仍是進行不一樣數據源之間的遷移,都不是很方便。而在.Net2.0中,SQLClient命名空間下增長了幾個新類幫助咱們經過DataTable或DataReader批量遷移數據。數據源能夠來自關 係數據庫或者XML文件,甚至WebService返回結果。其中最重要的一個類就是SqlBulkCopy類,使用它能夠很方便的幫助咱們把數據源的數 據遷移到目標數據庫中。

SQL Server  SqlBulkCopy 的使用,高效率批量插入數據。方法筆記,未測。sql

class SqlBulk
    {
        /// <summary>
        /// 向數據庫目標表中插入數據
        /// </summary>
        /// <param name="sourceTable">源數據DataTable</param>
        /// <param name="connectStr">數據庫鏈接字符串</param>
        /// <param name="destinationTableName">數據庫中的目標表名</param>
        /// <returns>是否成功</returns>
        public bool SqlBulkInsert(DataTable sourceTable, string connectStr, string destinationTableName)
        {
            try
            {
                SqlConnection conn = new SqlConnection(connectStr);
                SqlBulkInsert(sourceTable, conn, destinationTableName);
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {

            }
            return true;
        }
        /// <summary>
        /// 向數據庫目標表中插入數據
        /// </summary>
        /// <typeparam name="T">源數據的基本數據類型</typeparam>
        /// <param name="sourceList">源數據列表</param>
        /// <param name="connectStr">數據庫鏈接字符串</param>
        /// <param name="destinationTableName">數據庫中的目標表名</param>
        /// <returns>是否成功</returns>
        public bool SqlBulkInsert<T>(List<T> sourceList, string connectStr, string destinationTableName) where T:new ()
        {
            try
            {
                SqlConnection conn = new SqlConnection(connectStr);
                DataTable sourceTable=new DataTable();
                sourceTable = ListToDataTable<T>(sourceList, sourceTable);
                SqlBulkInsert(sourceTable, conn, destinationTableName);
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {

            }
            return true;
        }
        /// <summary>
        /// 向數據庫目標表中插入數據
        /// </summary>
        /// <typeparam name="T">源數據的基本數據類型</typeparam>
        /// <param name="sourceList">源數據列表</param>
        /// <param name="conn">未打開的數據庫鏈接</param>
        /// <param name="destinationTableName">數據庫中的目標表名</param>
        /// <returns>是否成功</returns>
        public bool SqlBulkInsert<T>(List<T> sourceList, SqlConnection conn, string destinationTableName) where T:new ()
        {
            try
            {
                DataTable sourceTable = new DataTable();
                sourceTable = ListToDataTable<T>(sourceList, sourceTable);
                SqlBulkInsert(sourceTable, conn, destinationTableName);

            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {

            }
            return true;
        }
        /// <summary>
        /// 向數據庫目標表中插入數據
        /// </summary>
        /// <param name="sourceTable">源數據DataTable</param>
        /// <param name="conn">未打開的數據庫鏈接</param>
        /// <param name="destinationTableName">數據庫中的目標表名</param>
        /// <returns>是否成功</returns>
        public bool SqlBulkInsert(DataTable sourceTable, SqlConnection conn, string destinationTableName)
        {
            DataSet ds = new DataSet();
            using (SqlConnection _conn=new SqlConnection(conn.ConnectionString))
            {
                _conn.Open();
                SqlCommand cmd = new SqlCommand("SELECT TOP 0 * FROM " + destinationTableName, conn);
                SqlDataAdapter da = new SqlDataAdapter(cmd);
                da.Fill(ds);
                da.Dispose();
            }
            foreach (DataColumn col in ds.Tables[0].Columns)
            {
                if (!sourceTable.Columns.Contains(col.ColumnName))
                {
                    throw new Exception("源數據表結構與目標表結構不對應");
                }
            }
            SqlBulkCopy sbc = new SqlBulkCopy(conn);
            try
            {
                sbc.BulkCopyTimeout = 1800;
                sbc.DestinationTableName = destinationTableName;
                sbc.BatchSize = 1000;
                sbc.NotifyAfter = 1;
                sbc.SqlRowsCopied += new SqlRowsCopiedEventHandler(sbc_SqlRowsCopied);
                foreach (DataColumn col in ds.Tables[0].Columns)
                {
                    sbc.ColumnMappings.Add(col.ColumnName, col.ColumnName);
                }
                conn.Open();
                sbc.WriteToServer(sourceTable);
                sbc.Close();
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                sbc.Close();
                conn.Close();
            }
            return true;
        }

        void sbc_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
        {
            //Console.WriteLine(e.RowsCopied + "rows are copierd");
        }
        /// <summary>
        /// 根據目標數據表結構,將List中的數據儘可能填充到目標數據表
        /// </summary>
        /// <typeparam name="T">數據類型</typeparam>
        /// <param name="list">數據列表</param>
        /// <param name="dt">數據表</param>
        /// <returns>返回數據表</returns>
        private DataTable ListToDataTable<T>(List<T> list, DataTable dt) where T : new()
        {
            dt.Clear();
            foreach (var item in list)
            {
                DataRow dr = dt.NewRow();
                foreach (var prop in typeof(T).GetProperties())
                {
                    if (dt.Columns.Contains(prop.Name))
                    {
                        dr[prop.Name] = prop.GetValue(item, null);
                    }
                }
                dt.Rows.Add(dr);
            }
            return dt;
        }
    }
使用SqlBulkCopy類進行數據插入其原理是採用了SQL Server的BCP協議進行數據的批量複製。這裏咱們先要建好一個DataTable(最好是經過DataAdapter來灌數據獲得,由於這樣出來的DataTable就已經有跟數據表相同的列定義,能夠免去以後Mapping Column的步驟),把要插入的數據加進這個DataTable中,而後用SqlBulkCopy的實例來插入到數據庫中。通過測試,SqlBulkCopy方法比直接用Sql語句插入數據的效率高出將近25倍。     另外批量導入SQL、MYSQL等數據是一樣的for循環,使用拼出來的sql或者使用參數的方式傳遞或者使用事務等不一樣方式的傳遞效率都不一樣。若是不使用SqlBulkCopy的方式的話,我測試下來作快遞是用一次事務來操做爲最快。由於10000次的循環若是是每次提交,那麼都有連接和中止數據庫的操做,或者說他包含了1000次的小事務處理。若是外面就一個事務的話效率確定會高。
相關文章
相關標籤/搜索