詳解MySqlBulkLoader的使用
mysql數(shù)據(jù)庫:最近要寫一個服務(wù),跨庫數(shù)據(jù)同步,目前數(shù)據(jù)量大約一萬,以后會越來越多,考慮到擴(kuò)展性,數(shù)據(jù)的插入操作就采用了MySqlBulkLoader。本文分兩部分來寫,第一部分寫一下MySqlBulkLoader的使用,第二部分記錄使用過程中出現(xiàn)的問題。
一、MySqlBulkLoader的使用
我們先來定義個數(shù)據(jù)表student,表結(jié)構(gòu)如下:
創(chuàng)建一個core控制臺項(xiàng)目,相關(guān)代碼如下:
入口代碼:
using System; using System.Collections.Generic; namespace MySqlBulkLoaderDemo { class Program { static void Main(string[] args) { //裝載30個數(shù)據(jù) List<Student> stuList = new List<Student>(); for (int i = 0; i < 30; i++) { stuList.Add( new Student { Guid = Guid.NewGuid().ToString(), Name = "QXH", Age = new Random().Next(1, 30) }); } //調(diào)用MySqlBulkLoader,往student表中插入stuList int insertCount = MySqlBulkLoaderHelper.BulkInsert<Student>(stuList, "student"); Console.WriteLine($"成功插入{insertCount}條數(shù)據(jù)"); Console.ReadKey(); } } }
定義一個Student映射類:
using System; using System.Collections.Generic; using System.Text; namespace MySqlBulkLoaderDemo { public class Student { public string Guid { get; set; } public string Name { get; set; } public int Age { get; set; } } }
定義一個MySqlBulkLoaderHelper類,用于存放相關(guān)方法:
using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data; using System.IO; using System.Linq; using System.Text; namespace MySqlBulkLoaderDemo { public class MySqlBulkLoaderHelper { const string ConnectionString = "server=localhost;port=3306;user=root;password=123456;database=mysql;SslMode = none;AllowLoadLocalInfile=true"; public static int BulkInsert<T>(List<T> entities, string tableName) { DataTable dt = entities.ToDataTable(); using (MySqlConnection conn = new MySqlConnection()) { conn.ConnectionString = ConnectionString; if (conn.State != ConnectionState.Open) { conn.Open(); } if (tableName.IsNullOrEmpty()) { var tableAttribute = typeof(T).GetCustomAttributes(typeof(TableAttribute), true).FirstOrDefault(); if (tableAttribute != null) tableName = ((TableAttribute)tableAttribute).Name; else tableName = typeof(T).Name; } int insertCount = 0; string tmpPath = Path.Combine(Path.GetTempPath(), DateTime.Now.Ticks.ToString() + "_" + Guid.NewGuid().ToString() + ".tmp"); string csv = dt.ToCsvStr(); File.WriteAllText(tmpPath, csv, Encoding.UTF8); using (MySqlTransaction tran = conn.BeginTransaction()) { MySqlBulkLoader bulk = new MySqlBulkLoader(conn) { FieldTerminator = ",", FieldQuotationCharacter = '"', EscapeCharacter = '"', LineTerminator = "\r\n", FileName = tmpPath, Local = true, NumberOfLinesToSkip = 0, TableName = tableName, CharacterSet = "utf8" }; try { bulk.Columns.AddRange(dt.Columns.Cast<DataColumn>().Select(colum => colum.ColumnName).ToList()); insertCount = bulk.Load(); tran.Commit(); } catch (MySqlException ex) { if (tran != null) tran.Rollback(); throw ex; } } File.Delete(tmpPath); return insertCount; } } } }
定義一個幫助類ExtentionHelper,主要是擴(kuò)展方法:
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Data; using System.Text; namespace MySqlBulkLoaderDemo { public static class ExtentionHelper { /// <summary> /// 將對象序列化成Json字符串 /// </summary> /// <param name="obj">需要序列化的對象</param> /// <returns></returns> public static string ToJson(this object obj) { return JsonConvert.SerializeObject(obj); } /// <summary> /// 將Json字符串轉(zhuǎn)為DataTable /// </summary> /// <param name="jsonStr">Json字符串</param> /// <returns></returns> public static DataTable ToDataTable(this string jsonStr) { return jsonStr == null ? null : JsonConvert.DeserializeObject<DataTable>(jsonStr); } /// <summary> /// 將IEnumerable'T'轉(zhuǎn)為對應(yīng)的DataTable /// </summary> /// <typeparam name="T">數(shù)據(jù)模型</typeparam> /// <param name="iEnumberable">數(shù)據(jù)源</param> /// <returns>DataTable</returns> public static DataTable ToDataTable<T>(this IEnumerable<T> iEnumberable) { return iEnumberable.ToJson().ToDataTable(); } /// <summary> /// 判斷是否為Null或者空 /// </summary> /// <param name="obj">對象</param> /// <returns></returns> public static bool IsNullOrEmpty(this object obj) { if (obj == null) return true; else { string objStr = obj.ToString(); return string.IsNullOrEmpty(objStr); } } /// <summary> ///將DataTable轉(zhuǎn)換為標(biāo)準(zhǔn)的CSV字符串 /// </summary> /// <param name="dt">數(shù)據(jù)表</param> /// <returns>返回標(biāo)準(zhǔn)的CSV</returns> public static string ToCsvStr(this DataTable dt) { //以半角逗號(即,)作分隔符,列為空也要表達(dá)其存在。 //列內(nèi)容如存在半角逗號(即,)則用半角引號(即"")將該字段值包含起來。 //列內(nèi)容如存在半角引號(即")則應(yīng)替換成半角雙引號("")轉(zhuǎn)義,并用半角引號(即"")將該字段值包含起來。 StringBuilder sb = new StringBuilder(); DataColumn colum; foreach (DataRow row in dt.Rows) { for (int i = 0; i < dt.Columns.Count; i++) { colum = dt.Columns[i]; if (i != 0) sb.Append(","); if (colum.DataType == typeof(string) && row[colum].ToString().Contains(",")) { sb.Append("\"" + row[colum].ToString().Replace("\"", "\"\"") + "\""); } else sb.Append(row[colum].ToString()); } sb.AppendLine(); } return sb.ToString(); } } }
完整項(xiàng)目:MySqlBulkLoaderDemo
運(yùn)行結(jié)果如下:
二、MySqlBulkLoader使用過程中出現(xiàn)的問題
上邊已經(jīng)完整了介紹了MySqlBulkLoader的使用,但是在使用過程中出現(xiàn)了很多問題,主要集中在兩方面,第一個方面是Mysql數(shù)據(jù)庫不支持加載本地文件數(shù)據(jù);第二個方面是我的數(shù)據(jù)庫在阿里云服務(wù)器上,而代碼在本地,換句話說數(shù)據(jù)庫和項(xiàng)目是分別放在不同服務(wù)器上的。
1、Mysql數(shù)據(jù)庫不支持加載本地文件數(shù)據(jù)
(1)MySQLBulkLoader原理?
我們結(jié)合SQLBulkCopy來說,用過SqlServer數(shù)據(jù)庫的都熟悉SQLBulkCopy,很方便,可以直接將datatable中的數(shù)據(jù)批量導(dǎo)入到數(shù)據(jù)庫。與SQLBulkCopy不同,MySQLBulkLoader也稱為LOAD DATA INFILE,他要從文件讀取數(shù)據(jù),所以我們需要將我們的數(shù)據(jù)集(如上邊的List<Student>)保存到文件,然后再從文件里面讀取。而對于Mysql來說,為了數(shù)據(jù)庫的安全,本地導(dǎo)入文件的配置沒有開啟,所以使用MySQLBulkLoader批量導(dǎo)入數(shù)據(jù)庫,就需要mysql數(shù)據(jù)庫支持本地導(dǎo)入文件。否則會出現(xiàn)以下錯誤:
The used command is not allowed with this MySQL version
(2)解決方案
mysql數(shù)據(jù)庫開啟允許本地導(dǎo)入數(shù)據(jù)的配置,命令如下:
SET GLOBAL local_infile=1;//1表示開啟,0表示關(guān)閉
查看該配置的狀態(tài)命令如下:
SHOW VARIABLES LIKE '%local%';
在項(xiàng)目里面的數(shù)據(jù)庫連接字符串做設(shè)置
數(shù)據(jù)庫連接字符串要加上”AllowLoadLocalInfile=true“,如下:
const string ConnectionString = "server=localhost;port=3306;user=root;password=123456;database=mysql;SslMode = none;AllowLoadLocalInfile=true";
2、數(shù)據(jù)庫和項(xiàng)目是分別放在不同服務(wù)器上
(1)問題描述
數(shù)據(jù)庫和項(xiàng)目是分別放在不同服務(wù)器上,會造成以下問題:
System.NotSupportedException HResult=0x80131515 Message=To use MySqlBulkLoader.Local=true, set AllowLoadLocalInfile=true in the connection string. See https://fl.vu/mysql-load-data
(2)原因
因?yàn)轫?xiàng)目中將數(shù)據(jù)集生成的文件保存在了項(xiàng)目所在的服務(wù)器,另一個服務(wù)器上的數(shù)據(jù)庫在插入數(shù)據(jù)操作時,找不到數(shù)據(jù)集文件,導(dǎo)致的錯誤
(3)解決方法
方法很簡單,因?yàn)閿?shù)據(jù)庫并不在項(xiàng)目所在的服務(wù)器,所以MySqlBulkLoader中要設(shè)置Local = true
讀取本地文件,進(jìn)行導(dǎo)入。具體代碼如下:
(4)總結(jié)
如果你的項(xiàng)目和數(shù)據(jù)庫在一臺服務(wù)器上,那么就不會出現(xiàn)該問題。
相關(guān)文章
MySQL安裝與配置:手工配置MySQL(windows環(huán)境)過程
這篇文章主要介紹了MySQL安裝與配置:手工配置MySQL(windows環(huán)境)過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12超詳細(xì)匯總21個值得收藏的mysql優(yōu)化實(shí)踐
這篇文章主要分享的是超詳細(xì)匯總21個值得收藏的mysql優(yōu)化實(shí)踐,對正在學(xué)習(xí)的同學(xué)有一定的參考價值,需要的同學(xué)可以參考一下2022-01-01數(shù)據(jù)庫管理中19個MySQL優(yōu)化方法
小編給大家總結(jié)了19條非常實(shí)用的MySQL數(shù)據(jù)庫優(yōu)化方法,這是每個服務(wù)器管理人員都必須知道的,一起學(xué)習(xí)下。2017-11-11