[转]C#:用SqlBulkCopy来实现批量插入数据

SqlBulkCopy是.net2.0的新特性,平时用的很少,但是其功能却是非常强大,对于批量插入数据性能非常优越

private void BulkInsert()
    {
        SqlConnection sqlcon
 = new SqlConnection("Data Source=LocalHost;Integrated Security=SSPI;Initial Catalog=xiaotest;");
         DateTime beginTime
 = DateTime.Now;
     
        DataTable dt
 = new DataTable();
        dt.Columns.Add(
"n", typeof(string));
        dt.Columns.Add(
"name", typeof(string));
       
 for (int i = 1; i <</SPAN> 1000; i++)
        {
            DataRow r = dt.NewRow();
            r["n"] = i;
            r["name"] = "xiao";
            dt.Rows.Add(r);
        }
     
        sqlcon.Open();

        using (SqlBulkCopy bulk = new SqlBulkCopy("Data Source=LocalHost;Integrated Security=SSPI;Initial Catalog=xiaotest;"))
        {
            bulk.BatchSize = 1000;
            bulk.DestinationTableName = "test2";
            bulk.ColumnMappings.Add("n""n");
            bulk.ColumnMappings.Add("name""name");
            bulk.WriteToServer(dt);
        }

      
        DateTime endTime = DateTime.Now;
        TimeSpan useTime = endTime - beginTime;
        dt.Dispose();
        time = "使用时间" + useTime.TotalSeconds.ToString() + "";
        sqlcon.Close();
        sqlcon.Dispose();
}

经过1000条数据的对比测试,一般性的循环插入与sqlbulk插入的时间对比为:

一般插入:使用时间0.5200008秒

使用builk插入:使用时间0.02秒

性能非常优越

 

另一种写法:

首先说一下,IProvider里有一个用于实现批量插入的插件服务接口IBatcherProvider,此接口在前一篇文章中已经提到过了。

 

    /// <summary>
    
/// 提供数据批量处理的方法。
    
/// </summary>
    public interface IBatcherProvider : IProviderService
    {
        /// <summary>
        
/// 将 <see cref="DataTable"/> 的数据批量插入到数据库中。
        
/// </summary>
        
/// <param name="dataTable">要批量插入的 <see cref="DataTable"/></param>
        
/// <param name="batchSize">每批次写入的数据量。</param>
        void Insert(DataTable dataTable, int batchSize = 10000);
    }

 

    一、SqlServer数据批量插入

    SqlServer的批量插入很简单,使用SqlBulkCopy就可以,以下是该类的实现:

 

    /// <summary>
    
/// 为 System.Data.SqlClient 提供的用于批量操作的方法。
    
/// </summary>
    public sealed class MsSqlBatcher : IBatcherProvider
    {
        /// <summary>
        
/// 获取或设置提供者服务的上下文。
        
/// </summary>
        public ServiceContext ServiceContext { getset; }

        /// <summary>
        
/// 将 <see cref="DataTable"/> 的数据批量插入到数据库中。
        
/// </summary>
        
/// <param name="dataTable">要批量插入的 <see cref="DataTable"/></param>
        
/// <param name="batchSize">每批次写入的数据量。</param>
        public void Insert(DataTable dataTable, int batchSize = 10000)
        {
            Checker.ArgumentNull(dataTable, "dataTable");
            if (dataTable.Rows.Count == 0)
            {
                return;
            }
            using (var connection = (SqlConnection)ServiceContext.Database.CreateConnection())
            {
                try
                {
                    connection.TryOpen();
                    //给表名加上前后导符
                    var tableName = DbUtility.FormatByQuote(ServiceContext.Database.Provider.GetService<ISyntaxProvider>(), dataTable.TableName);
                    using (var bulk = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, null)
                        {
                            DestinationTableName = tableName, 
                            BatchSize = batchSize
                        })
                    {
                        //循环所有列,为bulk添加映射
                        dataTable.EachColumn(c => bulk.ColumnMappings.Add(c.ColumnName, c.ColumnName), c => !c.AutoIncrement);
                        bulk.WriteToServer(dataTable);
                        bulk.Close();
                    }
                }
                catch (Exception exp)
                {
                    throw new BatcherException(exp);
                }
                finally
                {
                    connection.TryClose();
                }
            }
        }
    }

 

     SqlBulkCopy的ColumnMappings中列的名称受大小写敏感限制,因此在构造DataTable的时候应请注意列名要与表一致。

     以上没有使用事务,使用事务在性能上会有一定的影响,如果要使用事务,可以设置SqlBulkCopyOptions.UseInternalTransaction。

 

再另一种写法:

string connectionString = @"Server=Y203-01\SQLEXPRESS;database=InternetDB;uid=sa;pwd=121800;Max Pool Size = 512;";   
            DateTime time = DateTime.Now;   
            SqlBulkCopy sqlBC = new SqlBulkCopy(connectionString, SqlBulkCopyOptions.UseInternalTransaction);   
            sqlBC.DestinationTableName = "Tianya_Users";   
            DataTable dt = new DataTable("Tianya_Users");   
            dt.Columns.Add("ID", typeof(int));   
            dt.Columns.Add("UserName", typeof(string));   
            dt.Columns.Add("PassWord", typeof(string));   
            dt.Columns.Add("Email", typeof(string));   
            DirectoryInfo direct = new DirectoryInfo(@"D:\tianya");   
            string[] userInfo;   
            string readStr;   
            int totalNum = 0;   
            int partNum = 0;   
            int totalError = 0;   
            int partError = 0;   
            foreach (FileInfo NextFile in direct.GetFiles())   
            {   
                partNum = 0;   
                partError = 0;   
                Console.WriteLine("正在读取文件:" + NextFile.FullName);   
                StreamReader sr = new StreamReader(NextFile.FullName, Encoding.Default);//必须要指定编码格式,否则中文会乱码,应该可以用UTF-8   
                while (sr.Peek() > -1)   
                {   
                    totalNum++;   
                    partNum++;   
                    readStr = sr.ReadLine();   
                    userInfo = readStr.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);   
                    try  
                    {   
  
                        if (userInfo.Length < 1) continue;   
                        if (userInfo.Length < 2)   
                            dt.Rows.Add(0, userInfo[0].Trim(), DBNull.Value, DBNull.Value);   
                        else if (userInfo.Length < 3)   
                            dt.Rows.Add(0, userInfo[0].Trim(), userInfo[1].Trim(), DBNull.Value);   
                        else  
                            dt.Rows.Add(0, userInfo[0].Trim(), userInfo[1].Trim(), userInfo[2].Trim());   
                    }   
                    catch (Exception e1)   
                    {   
                        Console.WriteLine(e1.Message);   
                        totalError++;   
                        partError++;   
                    }   
                    //if (partNum % 100000 == 0) //每读10W条写入到数据库一次   
                    //{   
                    //    sqlBC.WriteToServer(dt);   
                    //    dt.Clear();   
                    //}   
                }   
                sqlBC.WriteToServer(dt);   
                Console.WriteLine("文件" + NextFile.FullName + "转换完成。本文件共有:" + partNum + " 条数据,其中失败:" + partError + " 条");   
                dt.Clear();   
                sr.Close();   
            }   
            dt.Dispose();   
            sqlBC.Close();   
            Console.WriteLine("转换完成。文件共有:" + totalNum + " 条数据,其中失败:" + totalError + " 条");   
            Console.WriteLine("共耗时:" + (DateTime.Now - time).TotalSeconds.ToString() + " 秒");   


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值