浅谈OracleBulkCopy的使用
考虑到前端应用往数据库里面插入数据,可以采用三种方式。
第一种:
直接在程序代码里面写入SQL,这种方式处理简单,然后这种方式的效率很低,因为应用程序每次都需要把SQL传递给数据库服务器,
然后数据库服务器解析,如果在一个循环内部不断的使用SQL访问数据库,那么需要不断的解析,因此会消耗很长的时间,同时,使用拼接SQL语句方式实现数据写入时,
由于SQL语句是动态执行的,所以恶意用户可以通过拼接SQL的方式实施SQL注入攻击。
第二种方法: 存储过程
优点:与SQL语句相比,存储过程存在很多优势。存储过程允许标准组件式编程,能够实现较快的执行速度,能够减少网络流量,而且可被作为一种安全机制来充分利用,存储过程由于在服务端编译过了,相比较直接使用SQL的方式,省去了SQL的解析过程,因此有很高的时间效率。
缺点:由于其实现方式是利用数据库访问类调用存储过程,利用循环逐条插入,所以这种方式的效率不高。还有两个方面是他的可移植性和可扩展性,因为一般大型的Web应用程序都是多Web服务器,然后用双数据库服务器做双机热备,其中一台开机,但是是闲置的。这里只是解决单点故障的问题,但形成了多Web应用服务器,单数据库服务器的情况。如果所有的运算都用存储过程实现,那么会造成数据库服务器负担过重。而Web服务器负荷不足的情况,扩展数据库服务器的话就会非常的麻烦,而且投资较大,程序也需要改。
第三种方式,使用OracleBulkCopy
OracleBulkCopy是ODP.NET中的一个类,是ODP.NET才有的功能。
优点:调用WriteToServer方法,可以快速有效的实现大数据量导入数据库。OracleBulkCopy支持超大文本的导入,支持从数据中的某一行开始导入,可以决定是否保存数据行号,列映射不区分大小写,支持导入常量列,支持源列自动检测,当相同源列导入多目标列时,只分配一次内存,更加节约内存。
OracleBulkCopy使用方法也非常简单
1. 构造数据表 DataTable dt = new DataTable();
2. 为数据表添加列:
dt.Columns.Add(Mappings.Fields.period_name, typeof(string)); --Mapping.Fields当中记录了要插入数据表的字段名称,这里取和数据库表的名称一致(不是必要的,以后后面还需要一个DataTable和数据库表的列名映射)
dt.Columns.Add(Mappings.Fields.ledger_id, typeof(int));
这里需要注意的地方是,一定要加入列的类型,如后面的typeof(int),如果不加入的话,默认列的类型是string,会导致批量插入数据出错。
3. 为数据表填充数据
foreach (PSGLGEArg rec in records.ApplyRecord)
{
DataRow dr = dt.NewRow();
dr[Mappings.Fields.period_name] = rec.period_name;
dr[Mappings.Fields.ledger_id] = rec.ledger_id;
dt.Rows.Add(dr);
}
4. 构造一个 OracleBulkCopy对象。
OracleBulkCopy bulkCopy = new OracleBulkCopy(connStr, OracleBulkCopyOptions.UseInternalTransaction);
这里需要注意的地方是,connStr是连接字符串,OracleBulkCopy 的连接字符串和普通的Oracle连接字符串之间存在区别。比如不支持:unicode=true.
连接字符串例子: "data source=dev;User Id=dyc;Password=1234;Max Pool Size=100;Min Pool Size=5;"
第二个参数是使用OracleBulkCopy内部的事务,保证数据插入的一致性。
5. 填充OracleBulkCopy对应的表名,和DataTable与数据库表列的映射关系。
foreach (DataColumn col in dt.Columns)
{
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
}
7. 最后一步,把构造的数据表当中的数据写入到数据库中。
bulkCopy.WriteToServer(dt);
bulkCopy.Dispose();