当前位置: 首页 > 技术 > 正文

采用SqlBulkCopy批量导入

黑墨 - 2015-03-18 分类:技术 C# 数据导入 SqlBulkCopy
4253

    平时在用到批量导入的时候,我们可能会采循环语句导入,殊不知这种导入方式的最大缺点就是慢!
 

    如果你内存中的数据刚好是个DataTable时,下面这种方法不妨可以一试!真的是百万条数据只需几秒!  


    主角:SqlBulkCopy  


    直接上代码:
  

using System;  
using System.Collections.Generic;  
using System.Text;  
using System.Data;  
using System.Data.SqlClient;  
   
namespace BulkImport  
{  
    public delegate void NotifyAfterEventHandler(object sender, NotifyAfterEventArgs e);  
   
    public class SqlBulkImport  
    {  
        public event NotifyAfterEventHandler Notify;  
   
        protected virtual void OnNotify(NotifyAfterEventArgs e)  
        {  
            if (Notify != null)  
            {  
                Notify(this, e);  
            }  
        }  
   
        public static int SqlRowsCopied;  
        /// <summary>  
        ///  
        /// </summary>  
        /// <param name="dt"></param>  
        /// <param name="TabelName"></param>  
        /// <param name="conn"></param>  
        /// <param name="ColumnMappings"></param>  
        /// <param name="NotifyAfter">多少行一呼叫</param>  
        /// <returns></returns>  
        public string Import(DataTable dt, string TabelName, SqlConnection conn, Dictionary<string, string> ColumnMappings, int NotifyAfter = 0)  
        {  
   
            string re = dt.Rows.Count.ToString();  
            //声明数据库连接  
            try  
            {  
                conn.Open();  
            }  
            catch (Exception ex)  
            {  
                return ex.Message;  
            }  
            //声明SqlBulkCopy ,using释放非托管资源  
            using (SqlBulkCopy sqlBC = new SqlBulkCopy(conn))  
            {  
                //一次批量的插入的数据量  
                sqlBC.BatchSize = 1000;  
                //超时之前操作完成所允许的秒数,如果超时则事务不会提交 ,数据将回滚,所有已复制的行都会从目标表中移除  
                sqlBC.BulkCopyTimeout = 60;  
                sqlBC.NotifyAfter = NotifyAfter;  
                //設定 NotifyAfter 属性,以便在每插入10000 条数据时,呼叫相应事件。   
                sqlBC.SqlRowsCopied += new SqlRowsCopiedEventHandler(sqlBC_SqlRowsCopied);  
                //设置要批量写入的表  
                sqlBC.DestinationTableName = TabelName;  
                foreach (KeyValuePair<string, string> aa in ColumnMappings)  
                {  
                    sqlBC.ColumnMappings.Add(aa.Key, aa.Value);  
                }  
                //批量写入  
                try  
                {  
                    sqlBC.WriteToServer(dt);  
                }  
                catch (Exception ex)  
                {  
                    re = ex.Message;  
                }  
                finally  
                {  
                    conn.Dispose();  
                }  
            }  
            return re;  
        }  
   
        public void sqlBC_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)  
        {  
            NotifyAfterEventArgs e1 = new NotifyAfterEventArgs(e.RowsCopied);  
            OnNotify(e1);  
            return;  
        }  
         
    }  
   
   
    public class NotifyAfterEventArgs : EventArgs  
    {  
        private long _reached;  
        public NotifyAfterEventArgs(long num)  
        {  
            this._reached = num;  
        }  
        public long SqlRowsCopiedCount  
        {  
            get  
            {  
                return _reached;  
            }  
        }  
    }  
}


 

调用方式:  


class Program  
    {  
        static void Main(string[] args)  
        {  
            DataTable dt = new DataTable();  
   
            dt.Columns.Add("编码");  
            dt.Columns.Add("名称");  
   
            for (int i = 0; i < 100000; i++)  
            {  
                var dr = dt.NewRow();  
                dr["编码"] = i;  
                dr["名称"] = string.Format("{0}名称,,,,,",i);  
   
                dt.Rows.Add(dr);  
            }  
   
   
            SqlBulkImport si = new SqlBulkImport();  
   
            si.Notify += si_Notify;  
   
            Dictionary<string,string> mapping =new Dictionary<string,string> ();  
   
            mapping.Add("Code","编码");  
            mapping.Add("Name","名称");  
   
   
            si.Import(dt, "myDt", youSqlConnection, mapping,100);  // 100 :定义每插入100条数据响应相应事件  
   
        }  
   
        static void si_Notify(object sender, NotifyAfterEventArgs e)  
        {  
             //可呼叫进度条。。。。  
        }  
    }