最近公司需要优化导入的问题,由于之前使用的方式是生成 Insert 语句插入数据库,数据量小的时候还行,但是随着发展数据量渐渐大了,之前的方法性能就跟不上了,于是发现了 SqlBulkCopy 这个类。

使用 SqlBulkCopy 类只能向 SQL Server 表写入数据。但是,数据源不限于 SQL Server;可以使用任何数据源,只要数据可加载到 DataTable 实例或可使用 IDataReader 实例读取数据。

public class Conn
{
private static string StrConn
{
get
{
return ConfigurationManager.ConnectionStrings["StrConn"].ToString();
//return ConfigurationManager.AppSettings["StrConn"].ToString();
}
} public static SqlConnection SqlConn
{
get
{
return new SqlConnection(StrConn);
}
}
} public class SqlHelper
{ public DataTable GetDataTable(string sql)
{
DataTable dt = new DataTable();
SqlConnection conn = null;
SqlDataAdapter sda = null;
try
{
conn = Conn.SqlConn;
sda = new SqlDataAdapter(sql, conn);
conn.Open();
sda.Fill(dt);
}
catch (Exception ex)
{ }
finally
{
if (conn != null)
{
conn.Close();
conn.Dispose();
}
if (sda != null)
{
sda.Dispose();
}
}
return dt;
} public DataSet GetDataSet(string sql)
{
DataSet ds = new DataSet();
SqlConnection conn = null;
SqlDataAdapter sda = null;
try
{
conn = Conn.SqlConn;
sda = new SqlDataAdapter(sql, conn);
conn.Open();
sda.Fill(ds);
}
catch (Exception ex)
{ }
finally
{
if (conn != null)
{
conn.Close();
conn.Dispose();
}
if (sda != null)
{
sda.Dispose();
}
}
return ds;
} /// <summary>
/// 使用事务插入方法
/// </summary>
/// <param name="dt">源数据</param>
/// <param name="tableName">目标表名</param>
public void InsertO(DataTable dt, string tableName)
{
using (SqlConnection conn = Conn.SqlConn)
{
using (SqlBulkCopy sqlBuleCopy = new SqlBulkCopy(conn.ConnectionString, SqlBulkCopyOptions.CheckConstraints | SqlBulkCopyOptions.Default | SqlBulkCopyOptions.UseInternalTransaction))
{
try
{
//设置目标表名,即数据库表名
sqlBuleCopy.DestinationTableName = tableName; //设置每一批次的行数,即达到指定的行数就插入一次数据库
sqlBuleCopy.BatchSize = ; //设置超时之前完成的时间(秒)
sqlBuleCopy.BulkCopyTimeout = ;
for (int i = ; i < dt.Columns.Count; i++)
{
//设置源数据列与目标表的列的映射关系,第一个参数为源数据列,第二个参数为目标表列
sqlBuleCopy.ColumnMappings.Add(dt.Columns[i].ColumnName, dt.Columns[i].ColumnName);
}
sqlBuleCopy.WriteToServer(dt);
}
catch (Exception)
{
}
}
}
} /// <summary>
/// 未使用事务插入方法
/// </summary>
/// <param name="dt">源数据</param>
/// <param name="tableName">目标表名</param>
public void InsertT(DataTable dt, string tableName)
{
using (SqlConnection conn = Conn.SqlConn)
{
using (SqlBulkCopy sqlBuleCopy = new SqlBulkCopy(conn))
{
try
{
conn.Open();
//设置目标表名,即数据库表名
sqlBuleCopy.DestinationTableName = tableName; //设置每一批次的行数,即达到指定的行数就插入一次数据库
sqlBuleCopy.BatchSize = ; //设置超时之前完成的时间(秒)
sqlBuleCopy.BulkCopyTimeout = ;
for (int i = ; i < dt.Columns.Count; i++)
{
//设置源数据列与目标表的列的映射关系,第一个参数为源数据列,第二个参数为目标表列
sqlBuleCopy.ColumnMappings.Add(dt.Columns[i].ColumnName, dt.Columns[i].ColumnName);
}
sqlBuleCopy.WriteToServer(dt);
}
catch (Exception)
{
conn.Close();
conn.Dispose();
}
finally
{
conn.Close();
conn.Dispose();
}
}
}
}
}

我的源数据是使用 Excel 导入的数据,导入的方法就不说了,不是这里的重点,之后我会专门总结一下 Excel 导入的方法。然后查询目标表需要插入数据的字段,修改源数据表的字段名和类型,然后调用批量插入的方法。

protected void btnImport_Click(object sender, EventArgs e)
{
try
{
//获取导入的数据
DataSet ds = BI.ExecleDs(savePath, "");
if (ds != null && ds.Tables.Count > )
{
DataTable dt = ds.Tables[]; //查询目标表需要插入的字段
string sql = " select U_No,U_Name,U_Pwd,P_Id from UserInfo ";
DataTable dt1 = sqlhelper.GetDataTable(sql); if (dt1 != null)
{
for (int i = ; i < dt1.Columns.Count; i++)
{
//修改源数据表的字段类型和字段名称
dt.Columns[i].DataType = dt1.Columns[i].DataType;
dt.Columns[i].ColumnMapping = dt1.Columns[i].ColumnMapping;
dt.Columns[i].ColumnName = dt1.Columns[i].ColumnName;
} sqlhelper.InsertO(dt, "UserInfo");
}
}
}
catch (Exception ex)
{ throw;
}
}

以上这种修改数据类型的方法,如果碰到数据类型不一致并且 DataTable 有数据的时候,会报错,不能修改有数据的列的数据类型。(好像是废话,嘿嘿,没有数据和有数据时不能修改数据类型,这完全是没用的。)

所以就有了下面的方法,先实例化一个新的 DataTable,然后复制目标表的架构,然后再把数据保存到新的 DataTable 中。

protected void btnImport_Click(object sender, EventArgs e)
{
try
{
//获取导入的数据
DataSet ds = BI.ExecleDs(savePath, "");
if (ds != null && ds.Tables.Count > )
{
DataTable dt = ds.Tables[]; //查询目标表需要插入的字段
string sql = " select U_No,U_Name,U_Pwd,P_Id from UserInfo ";
DataTable dt1 = sqlhelper.GetDataTable(sql);
DataTable dt2 = new DataTable(); if (dt1 != null)
{
//复制目标表的架构
dt2 = dt1.Clone(); for (int i = ; i < dt1.Rows.Count; i++)
{
DataRow dr = dt2.NewRow();
dr = dt1.Rows[i];
dt2.Rows.Add(dr.ItemArray);
} sqlhelper.InsertO(dt2, "UserInfo");
}
}
}
catch (Exception ex)
{ throw;
}
}

如果源数据表的列和目标表的列的顺序或列名不相同,那就必须使用 ColumnMappings.Add() 方法设置映射关系。

参考:

http://www.cnblogs.com/zfanlong1314/archive/2013/02/05/2892998.html

C# 使用 SqlBulkCopy 类批量复制数据到数据库的更多相关文章

  1. 用.net中的SqlBulkCopy类批量复制数据 (转载)

    在软件开发中,把数据从一个地方复制到另一个地方是一个普遍的应用. 在很多不同的场合都会执行这个操作,包括旧系统到新系统的移植,从不同的数据库备份数据和收集数据. .NET 2.0有一个SqlBulkC ...

  2. 使用asp.net 2.0中的SqlBulkCopy类批量复制数据

    介绍:在软件开发中,把数据从一个地方复制到另一个地方是一个普遍的应用. 在很多不同的场合都会执行这个操作,包括旧系统到新系统的移植,从不同的数据库备份数据和收集数据. ASP.NET 2.0有一个Sq ...

  3. C# 使用SqlBulkCopy类批量复制大数据

    用途说明: 前些日子,公司要求做一个数据导入程序,要求将Excel数据,大批量的导入到数据库中,尽量少的访问数据库,高性能的对数据库进行存储.于是在网上进行查找,发现了一个比较好的解决方案,就是采用S ...

  4. C# SqlBulkCopy类批量导入数据

    特别注意  sqlbulkcopy.ColumnMappings.Add(dt.Columns[i].ColumnName, dt.Columns[i].ColumnName); 插入的时候列的顺序可 ...

  5. 使用SqlBulkCopy类批量复制大数据

    using System; using System.Configuration; using System.Data; using System.Data.SqlClient; using Syst ...

  6. SqlBulkCopy 批量复制数据到数据库

    1.简介 1.MSDN 核心方法:SqlBulkCopy.WriteToServer 将所有行从数据源复制到 SqlBulkCopy 对象的 DestinationTableName 属性指定的目标表 ...

  7. SqlBulkCopy类进行大数据(一万条以上)插入测试

    好多天没写博客了,刚刚毕业一个多月! 关于上一篇博客中提到的,在进行批量数据插入数据库的时候可以通过给存储过程传递一个类型为Table的参数进行相关操作,在这个过程中本人没有进行效率的测试.后来查找发 ...

  8. SqlBulkCopy类进行大数据(10000万条以上)插入测试

    好多天没写博客了,刚刚毕业一个多月,在IT的路上真是迷茫啊! 关于上一篇博客中提到的,在进行批量数据插入数据库的时候可以通过给存储过程传递一个类型为Table的参数进行相关操作,在这个过程中本人没有进 ...

  9. 转:SqlBulkCopy类进行大数据(一万条以上)插入测试

    转自:https://www.cnblogs.com/LenLi/p/3903641.html 结合博主实例,自己测试了一下,把数据改为3万行更明显!! 关于上一篇博客中提到的,在进行批量数据插入数据 ...

随机推荐

  1. 【BZOJ】1044: [HAOI2008]木棍分割(二分+dp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1044 如果只求最大的最小,,直接二分就行了...可是要求方案.. 好神! 我竟然想不到! 因为我们得 ...

  2. 【BZOJ】1645: [Usaco2007 Open]City Horizon 城市地平线(线段树+特殊的技巧)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1645 这题的方法很奇妙啊...一开始我打了一个“离散”后的线段树.............果然爆了. ...

  3. mysql解决乱码问题

    进入mysql(mysql -u root -p),查看当前数据库字符集(status;) 刚开始是latin1,所以乱码. vim /etc/my.cnf 两个节点添加如下: [client]def ...

  4. wpf中用户控件的属性重用

    我们经常会抽取一些可重用的控件,某个属性是否需要重用,直接决定了这个属性的绑定方式. 1.完全不可重用的控件 有一些与业务强相关的控件,它们的属性完全来自ViewModel,越是相对复杂的控件,越容易 ...

  5. Tomcat服务器的安装与配置

    安装 输入网址进入Tomcat的官网            在左边导航栏选择对应下载的版本            下载安装包形式             下载并解压到我们欲放入的目录中 配置      ...

  6. hdu1059(多重背包优化)

    使用一种二进制的优化, 可以完美的解决这题,<背包九讲>中说的非常好 但是还有一种线性复杂的算法. 应该算是该题很巧妙的解法 ;i++) { ;l--) { ) continue; ;k& ...

  7. 延迟加载JavaScript

    上代码: 这段代码放到HTML文档的</body>标签之前(靠近HTML文档底部).外部脚本的名称为defer.js. <script type="text/javascr ...

  8. requireJs官方使用教程(转)

    原文地址:http://www.requirejs.cn § 1.使用 § 1.1 加载 JavaScript 文件 RequireJS的目标是鼓励代码的模块化,它使用了不同于传统<script ...

  9. 20165330 2017-2018-2 《Java程序设计》第8周学习总结

    课本知识总结 第十二章 Java多线程机制 Java中的线程 进程:是程序的一次动态执行过程,它对应了从代码加载.执行至执行完毕的一个完整过程 线程:一个进程在其执行过程中,可以产生多个线程,形成多条 ...

  10. BSSID,SSID,ESSID区别

    SSID(Service Set Identifier)   SSID,AP唯一的ID码,许多人认为可以将SSID写成ESSID,其实不然,SSID是个笼统的概念,包含了ESSID和BSSID,用来区 ...