網站首頁 編程語言 正文
文章描述
往數據庫批量寫入數據,這個功能使用頻率相對還是比較高的,特別是在做一些導入等功能的時候。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
相關推薦
- 2023-12-21 Redis HyperLogLog的使用
- 2022-07-18 Column count doesn’t match value count at row 1
- 2022-07-12 git如何上傳本地項目
- 2023-01-21 Python中的二維列表使用及說明_python
- 2022-11-09 CSS元素定位
- 2022-10-10 AOSP源碼下載示例代碼_Android
- 2023-07-26 vscode中配置代碼片段
- 2022-04-19 css塊級元素,行內元素和行內塊級元素
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支