大批量导入数据的SqlBulkCopy类
SqlBulkCopy 这个类用于数据库大批量的数据传递,通常用于新旧数据库之间的更新。关键的一点是,即使表结构不同,也可以通过表字段或者字段位置建立映射关系,将所需的数据导入到目标数据库。
下面代码测试了数据量为一百万条数据,几次测试耗时8秒左右。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /// <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 实例。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤