日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C#實現Oracle批量寫入數據的方法詳解_C#教程

作者:Csharp小記 ? 更新時間: 2022-12-04 編程語言

文章描述

往數據庫批量寫入數據,這個功能使用頻率相對還是比較高的,特別是在做一些導入等功能的時候。net的程序大部分都是使用的sqlserver或者mysql數據庫,oracle相對少一些。不過說到Oracle批量寫入數據,我只想吐槽一句: .Net苦Oracle久矣。

由于一直使用的是.Net Framework,所以我感覺Oracle在批量寫入這一塊很不友好。之前有使用過兩種方式,但是弊端太明顯。分別是: OracleDataAdapter.Update(DataTable dataTable)Oracle.DataAccess.Client下的OracleBulkCopy,以下簡單說下:

第一種感覺就是只是提供了一個批量提交的方式,在效率方面,并沒有什么提升;

第二種對Oracle環境配置的什么的有要求,所以我在使用的時候,把類似精簡oracle的一些文件放了進去(可能是這個原因),在初始化和Open的時候依然會卡頓一下。即便如此,這個方法依然很快。但是弊端基本無解,如非無奈,盡量不要使用(但是我們確實是無奈之舉,所以依然使用了一段時間,并采用了以下方式盡量避免這個問題,采用的方式是:批量寫入一個無主鍵的臨時表,然后把這個臨時表在業務、事務中使用)。

弊端1:沒有事務,只有一個內部事務(UseInternalTransaction),單純的用來保證此次提交數據的一次性而已。

弊端2:會破壞主鍵,即便數據主鍵重復依然可以寫入成功。導致表結構混亂,引發一系列問題?。?!

之前有在SqlSugar中看到Oracle的批量提交,他在備注有表明以上弊端,但是奇怪的是他同時標注了只支持.Net Core,但其實.Net Framework也是可以用。而且我沒明白既然只支持.Net Core,為什么不用我下面要寫的第三種方式

再然后偶爾在網上發現了第三種方式: .Net Core下,基于Oracle.ManagedDataAccess.Client中的ArrayBindCount,測試后發現,無上述弊端,效率比OracleBulkCopy更優秀。但是如果要繼承到老項目中的話,建議寫個插件或者Web Api來處理

開發環境

.NET Framework4.5、.NET Core 3.1

開發工具

Visual Studio 2019

實現代碼

//OracleDataAdapter.Update(DataTable dataTable)方式
using System.Data.OracleClient;
public static int BulkCopy(DataTable dataTable) {
            int result = 0;


            List<string> sql_column = new List<string>();
            List<string> sql_para = new List<string>();

            List<OracleParameter> paras = new List<OracleParameter>();
            foreach(DataColumn column in dataTable.Columns) {
                sql_column.Add(column.ColumnName);
                sql_para.Add(":" + column.ColumnName);

                OracleParameter para = new OracleParameter(column.ColumnName, ConvertOracleDbType(column.DataType));
                para.SourceColumn = column.ColumnName;
                paras.Add(para);
            }

            using(OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings["default"].ConnectionString)) {
                conn.Open();
                string sql = $"insert into {dataTable.TableName}({string.Join(",", sql_column)}) values ({string.Join(",", sql_para)})";
                OracleCommand cmd = new OracleCommand(sql, conn);
                cmd.Parameters.AddRange(paras.ToArray());
                OracleDataAdapter adapter = new OracleDataAdapter();
                adapter.InsertCommand = cmd;
                result = adapter.Update(dataTable);
                conn.Close();
            }
            return result;
        }

        public static OracleType ConvertOracleDbType(Type type) {
            switch(type.Name.ToLower()) {
                case "decimal":
                return OracleType.Number;
                case "string":
                return OracleType.VarChar;
                case "datetime":
                return OracleType.DateTime;
                default:
                return OracleType.VarChar;
            }
        }
//OracleBulkCopy
using Oracle.DataAccess.Client;
public static int BulkCopy(DataTable dataTable) {

            int result = 0;

            using(OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings["default"].ConnectionString)) {
                conn.Open();
                OracleBulkCopy oracleBulkCopy = new OracleBulkCopy(conn, OracleBulkCopyOptions.UseInternalTransaction);
                oracleBulkCopy.DestinationTableName = dataTable.TableName;

                foreach(DataColumn column in dataTable.Columns) {
                    oracleBulkCopy.ColumnMappings.Add(new OracleBulkCopyColumnMapping(column.ColumnName, column.ColumnName));
                }

                oracleBulkCopy.WriteToServer(dataTable);
                conn.Close();
            }
            return result;
        }
//ArrayBindCount
using Oracle.ManagedDataAccess.Client;
   public static OracleDbType ConvertOracleDbType(Type type) {
            switch(type.Name.ToLower()) {
                case "decimal":
                return OracleDbType.Decimal;
                case "string":
                return OracleDbType.Varchar2;
                case "datetime":
                return OracleDbType.Date;
                default:
                return OracleDbType.Varchar2;
            }
        }
        public static dynamic InitList(Type type) {
            switch(type.Name.ToLower()) {
                case "decimal":
                return new List<decimal>();
                case "string":
                return new List<string>();
                case "datetime":
                return new List<DateTime>();
                default:
                return new List<string>();
            }
        }
        public static void AddValue(dynamic list, Type type, object value) {
            switch(type.Name.ToLower()) {
                case "decimal":
                list.Add(Convert.ToDecimal(value));
                break;
                case "string":
                list.Add(Convert.ToString(value));
                break;
                case "datetime":
                list.Add(Convert.ToDateTime(value));
                break;
                default:
                list.Add(Convert.ToString(value));
                break;
            }
        }

        public static int BulkCopy(DataTable dataTable) {

            string connStr = "";
            int result = 0;

            List<string> sql_column = new List<string>();
            List<string> sql_para = new List<string>();

            List<OracleParameter> paras = new List<OracleParameter>();
            foreach(DataColumn column in dataTable.Columns) {

                sql_column.Add(column.ColumnName);
                sql_para.Add(":" + column.ColumnName);

                dynamic list = InitList(column.DataType);

                foreach(DataRow dr in dataTable.Rows) {
                    AddValue(list, column.DataType, dr[column]);
                }
                OracleParameter para = new OracleParameter(column.ColumnName, ConvertOracleDbType(column.DataType));
                para.Value = list.ToArray();
                paras.Add(para);
            }
            using(var connection = new OracleConnection(connStr)) {
                connection.Open();
                string sql = $"insert into {dataTable.TableName}({string.Join(",", sql_column)}) values ({string.Join(",", sql_para)})";
                OracleCommand cmd = new OracleCommand(sql, connection);
                cmd.Parameters.AddRange(paras.ToArray());
                cmd.ArrayBindCount = dataTable.Rows.Count;
                result = cmd.ExecuteNonQuery();
                connection.Close();
            }
            return result;
        }

代碼解析:連接Oracle的字符串盡量寫成Data Source=IP:Port/DB;User ID=USER;password=PWD;即便配置了tns文件。

上面的方式有做了一下效率比對(各個機器配置等不一致,僅供參考): ? ?

測試數據為5萬條,3列,第一種等了很久沒寫完,直接斷掉了;第二種和第三種都是4秒多一點。

原文鏈接:https://mp.weixin.qq.com/s/wdm0X4nOltKA98V175ovTA

相關推薦

欄目分類
最近更新