C#利用ODP.NET往oracle中高效插入百万数据
2015-10-21 11:23
585 查看
因工作的原因,要使用winform来处理大量的数据,但是c#自带的System.data.OracleClient效率不是很高,在网上找了很久,找到了ODP.NET,是oracle为c#提供的。貌似从vs2010开始,微软开始推荐使用ODP.NET。效率的话,在没有索引的情况下,100万数据,不到10秒。 1.从官网上下载ODAC,如果你是32位的机器,那下载32的;64位的,就下载64的。我的win7, 64位,所以我下载的是ODAC1120320_x64,具体地址: 64位:http://www.oracle.com/technetwork/database/windows/downloads/index-090165.html 32位:http://www.oracle.com/technetwork/developer-tools/visual-studio/downloads/index.html 2.解压,然后点击 setup.exe 安装,然后在这个地址:D:\app\12\product\11.2.0\client_1\odp.net\bin\2.x ![]() 双击 OraProvCfg.exe,会自动配置环境 ![]() 3.在安装的目录下,依次找到以下dll: oci.dll ociw32.dll Oracle.DataAccess.dll orannzsbb11.dll oraocci11.dll oraociicus11.dll OraOps11w.dll 然后将这些dll放到bin\debug目录下(这里是c/s项目,b/s的话貌似放在bin目录下) 4.在项目中,添加引用,就可以使用了,用法跟自带的System.data.OracleClient差不多 ![]() 5.批量插入: //设置一个数据库的连接串 string connectStr = "User Id=scott;Password=tiger;Data Source="; OracleConnection conn = new OracleConnection(connectStr); OracleCommand command = new OracleCommand(); command.Connection = conn; //到此为止,还都是我们熟悉的代码,下面就要开始喽 //这个参数需要指定每次批插入的记录数 command.ArrayBindCount = recc; //在这个命令行中,用到了参数,参数我们很熟悉,但是这个参数在传值的时候 //用到的是数组,而不是单个的值,这就是它独特的地方 command.CommandText = "insert into dept values(:deptno, :deptname, :loc)"; conn.Open(); //下面定义几个数组,分别表示三个字段,数组的长度由参数直接给出 int[] deptNo = new int[recc]; string[] dname = new string[recc]; string[] loc = new string[recc]; // 为了传递参数,不可避免的要使用参数,下面会连续定义三个 // 从名称可以直接看出每个参数的含义,不在每个解释了 OracleParameter deptNoParam = new OracleParameter("deptno", OracleDbType.Int32); deptNoParam.Direction = ParameterDirection.Input; deptNoParam.Value = deptNo; command.Parameters.Add(deptNoParam); OracleParameter deptNameParam = new OracleParameter("deptname", OracleDbType.Varchar2); deptNameParam.Direction = ParameterDirection.Input; deptNameParam.Value = dname; command.Parameters.Add(deptNameParam); OracleParameter deptLocParam = new OracleParameter("loc", OracleDbType.Varchar2); deptLocParam.Direction = ParameterDirection.Input; deptLocParam.Value = loc; command.Parameters.Add(deptLocParam); Stopwatch sw = new Stopwatch(); sw.Start(); //在下面的循环中,先把数组定义好,而不是像上面那样直接生成SQL for (int i = 0; i < recc; i++) { deptNo[i] = i; dname[i] = i.ToString(); loc[i] = i.ToString(); } //这个调用将把参数数组传进SQL,同时写入数据库 command.ExecuteNonQuery(); sw.Stop(); System.Diagnostics.Debug.WriteLine("批量插入:" + recc.ToString() + "所占时间:" +sw.ElapsedMilliseconds.ToString()); 6.上面的代码太乱,给一个已经封装好的批量插入的方法: /** * 批量插入数据 * @tableName 表名称 * @columnRowData 键-值存储的批量数据:键是列名称,值是对应的数据集合 * @conStr 连接字符串 * @len 每次批处理数据的大小 */ public static int BatchInsert(string tableName, Dictionary<string, object> columnRowData, string conStr, int len) { if (string.IsNullOrEmpty(tableName)) { throw new ArgumentException("必须指定批量插入的表名称", "tableName"); } if (columnRowData == null || columnRowData.Count < 1) { throw new ArgumentException("必须指定批量插入的字段名称", "columnRowData"); } int iResult = 0; string[] dbColumns = columnRowData.Keys.ToArray(); StringBuilder sbCmdText = new StringBuilder(); if (columnRowData.Count > 0) { //准备插入的SQL sbCmdText.AppendFormat("INSERT INTO {0}(", tableName); sbCmdText.Append(string.Join(",", dbColumns)); sbCmdText.Append(") VALUES ("); sbCmdText.Append(":" + string.Join(",:", dbColumns)); sbCmdText.Append(")"); using (OracleConnection conn = new OracleConnection(conStr)) { using (OracleCommand cmd = conn.CreateCommand()) { //绑定批处理的行数 cmd.ArrayBindCount = len; cmd.BindByName = true; cmd.CommandType = CommandType.Text; cmd.CommandText = sbCmdText.ToString(); cmd.CommandTimeout = 600;//10分钟 //创建参数 OracleParameter oraParam; List<IDbDataParameter> cacher = new List<IDbDataParameter>(); OracleDbType dbType = OracleDbType.Object; foreach (string colName in dbColumns) { dbType = GetOracleDbType(columnRowData[colName]); oraParam = new OracleParameter(colName, dbType); oraParam.Direction = ParameterDirection.Input; oraParam.OracleDbTypeEx = dbType; oraParam.Value = columnRowData[colName]; cmd.Parameters.Add(oraParam); } //打开连接 conn.Open(); /*执行批处理*/ var trans = conn.BeginTransaction(); try { cmd.Transaction = trans; iResult = cmd.ExecuteNonQuery(); trans.Commit(); } catch (Exception ex) { trans.Rollback(); throw ex; } finally { if (conn != null) conn.Close(); } } } } return iResult; } /** * 根据数据类型获取OracleDbType */ private static OracleDbType GetOracleDbType(object value) { OracleDbType dataType = OracleDbType.Object; if (value is string[]) { dataType = OracleDbType.Varchar2; } else if (value is DateTime[]) { dataType = OracleDbType.TimeStamp; } else if (value is int[] || value is short[]) { dataType = OracleDbType.Int32; } else if (value is long[]) { dataType = OracleDbType.Int64; } else if (value is decimal[] || value is double[] || value is float[]) { dataType = OracleDbType.Decimal; } else if (value is Guid[]) { dataType = OracleDbType.Varchar2; } else if (value is bool[] || value is Boolean[]) { dataType = OracleDbType.Byte; } else if (value is byte[]) { dataType = OracleDbType.Blob; } else if (value is char[]) { dataType = OracleDbType.Char; } return dataType; } 7.调用封装的方法: ![]() 8.完成。 对于服务器上的oracle版本问题,我们的是10g,但是我用的ODP是11g的,还是可以插入数据,没什么问题,貌似可以向下兼容 |
相关文章推荐
- 关于oracle中varchar2的最大长度
- 奋斗的小鸟——dogxuefeng Oracle——distinct的用法
- Oracle触发器调用外部java
- Oracle,mysql,SqlServer数据库连接设置
- 手动清理Oracle审计记录
- ORACLE 下载地址及OTL数据库工具
- oracle无法执行delete等命令
- oracle 9i使用闪回查询恢复数据库误删问题
- Oracle Standby Redo Log实验两则
- oracle pl/sql之游标
- oracle的坑(不定期更新)
- ADO链接ORACLE的配置 WIN10
- Oracle VDI 安装
- 从Oracle Public Yum为Oracle Linux建立本地的Yum源
- [笔记]--Oracle 终止expdp/impdp进程运行的方法
- oracle copy long
- hibernate调用oracle存储过程
- Oracle常用的数据操作函数
- oracle 9i使用闪回查询恢复数据库误删问题
- DDL语句、DML语句、TCL语句