
简介这份资源面向具备一定VB.NET基础的开发者尤其是需要处理数据迁移、批量入库或做小型数据工具的技术人员。它围绕“连接MySQL并导入CSV”这一常见需求给出可运行的示例工程帮助读者理解ADO.NET操作数据库与文件解析的完整链路。压缩包共29个文件约75KB以vb源码、vbproj工程文件、sln解决方案为主另含exe、dll、pdb等编译产物及resx、resources、settings等配置资源结构紧凑便于直接打开调试。内容涉及MySqlConnection连接字符串配置、TextFieldParser逐行解析CSV、MySqlCommand配合INSERT INTO批量写入、Try...Catch异常捕获、事务与分块导入的性能优化思路以及连接关闭与资源释放等关键环节。已有192人学习适合想快速掌握VB.NET读写MySQL与CSV导入技巧的读者参考借鉴。1. VB.NET 连 MySQL 导 CSV一个被低估的桌面数据管道场景手上有一批 CSV来源可能是设备导出、第三方系统对账文件、爬下来的行情数据格式固定但量不小同时公司内部又有一套 MySQL 库需要把这些数据落进去做后续查询和报表。这种活儿很多人第一反应是写个 Python 脚本但在一些以 VB.NET 为主的技术栈里——比如老一代 WinForm 内部工具、ERP 二次开发、工控上位机——直接在现有工程里加一个「选文件、连库、导入」的按钮反而是维护成本最低的做法。这个标题讲的正是这件事用 VB.NET 作为宿主语言通过 MySQL 连接器把本地 CSV 文件读进来再批量写进 MySQL 表里。它解决的不是什么高深问题而是「数据在文件里、目标在库里、中间缺一段可靠搬运」的日常需求。适合两类人一类是维护 VB.NET 桌面工具、需要给现有系统加导入功能的工程师另一类是想搞清楚 .NET 生态连 MySQL 到底该怎么配、参数怎么调、批量插入为什么会慢的从业者。下面按「环境怎么搭 → 连接怎么建 → CSV 怎么读 → 数据怎么写 → 坑在哪」的顺序讲透。2. 环境与驱动选型VB.NET 连 MySQL 到底装什么2.1 为什么是 MySql.Data 而不是别的驱动.NET 连 MySQL 常见有三条路官方 Connector/NET包名MySql.Data、社区维护的MySqlConnector、以及走 ODBC 的MySql ODBC Driver。三者都能用但落地时差别不小。MySql.Data是 Oracle 官方维护的 ADO.NET 驱动API 和SqlClient高度一致VB.NET 里MySqlConnection、MySqlCommand、MySqlDataAdapter这套写法几乎不用重新学文档和 Stack Overflow 上的存量答案也最多。缺点是它对 .NET Core/.NET 5 的异步支持历史上出过一些兼容问题老版本还会强依赖特定运行时。MySqlConnector是纯托管的开源实现异步性能更好对MySqlBulkCopy的支持也更完整近年在 .NET 社区口碑上升很快。如果你的工程是 .NET Framework 4.x 的老 WinForm用MySql.Data最省心如果是 .NET 6/8 的新项目我更倾向MySqlConnector。ODBC 那条路除非你要兼容 Access 或 Excel 的旧代码否则不推荐参数转义和类型映射的坑太多。选型结论老工程用MySql.Data新工程用MySqlConnector两者 API 基本可以互换本文示例以MySql.Data为主关键差异会单独标注。2.2 用 NuGet 装驱动的最小步骤VB.NET 工程装包不要手动拷 DLL直接走 NuGet。Visual Studio 里右键项目 → 管理 NuGet 程序包 → 浏览 → 搜MySql.Data→ 选稳定版安装。命令行方式# 在解决方案根目录执行PackageReference 方式推荐.NET Core/5 与新版 Framework 工程 dotnet add package MySql.Data # 如果工程是 packages.config 老式管理用 VS 的包管理器控制台 # Install-Package MySql.Data装完后在代码文件顶部引入命名空间Imports MySql.Data.MySqlClient Imports System.IO Imports System.Data逻辑说明MySql.Data.MySqlClient提供连接、命令、参数、批量复制等核心类型System.IO用于读 CSV 文件流System.Data提供DataTable后面批量导入会用到。参数说明dotnet add package默认拉最新稳定版如果目标机器是 Windows 7 或 .NET Framework 4.5需要显式指定兼容版本例如--version 8.0.33否则可能因为运行时版本不匹配在加载时抛FileLoadException。提示驱动版本要和 MySQL 服务端大致对齐。服务端 5.7 配 8.x 驱动通常没问题但服务端 8.0 用 6.x 老驱动可能遇到caching_sha2_password认证失败报错信息是Authentication method caching_sha2_password not supported。2.3 连接字符串里那几个必须调对的参数连接字符串是这类项目翻车最集中的地方。一个能用的模板Dim connStr As String Server192.168.1.20;Port3306;Databasesales_db; Uidapp_user;PwdYourPassword; CharSetutf8mb4;SslModeNone; AllowLoadLocalInfileTrue;ConnectionTimeout15;DefaultCommandTimeout120;逐项说明Server/PortMySQL 默认 3306改过端口必须显式写。Database目标库名不写的话后续 SQL 里得带库前缀。CharSetutf8mb4中文、emoji 都要靠它写成utf8在 MySQL 里其实是三字节的旧 utf8存 emoji 会截断。SslMode内网直连可以设None省掉证书握手跨公网必须用Required并配 CA否则明文传输。AllowLoadLocalInfile只有用LOAD DATA LOCAL INFILE或MySqlBulkCopy时才需要默认关闭是安全设计别为了省事全局打开。ConnectionTimeout/DefaultCommandTimeout前者是建连超时后者是单条命令执行超时批量导入时后者要放大否则大文件跑到一半报超时。3. 把 CSV 读进内存解析方式与编码陷阱3.1 三种读法的取舍File.ReadAllLines、TextFieldParser、CsvHelperCSV 看着简单真解析起来全是边界字段里有逗号、有换行、有引号转义、有 BOM。三种常见做法File.ReadAllLines加Split(,)是最快的写法但只适合「字段里绝对不含逗号和引号」的干净数据一旦某列是地址或备注直接错位。Microsoft.VisualBasic.FileIO.TextFieldParser是 VB.NET 自带的老牌解析器能正确处理引号包裹和字段内逗号不用装第三方包对 VB 工程特别友好。CsvHelper是 NuGet 上的成熟库支持强类型映射、自定义分隔符、编码自动识别字段多、结构复杂时最省事。我的建议字段少、格式稳定用TextFieldParser字段多、要映射到实体类用CsvHelperSplit只在临时脚本里用正式工具别碰。3.2 用 TextFieldParser 读带引号的 CSVImports Microsoft.VisualBasic.FileIO Public Function ReadCsv(path As String) As DataTable Dim dt As New DataTable() 先建列列名和 CSV 表头保持一致 Using parser As New TextFieldParser(path, System.Text.Encoding.UTF8) parser.TextFieldType FieldType.Delimited parser.SetDelimiters(,) parser.HasFieldsEnclosedInQuotes True 关键处理 a,b 这种字段 第一行当表头 If Not parser.EndOfData Then Dim headers parser.ReadFields() For Each h In headers dt.Columns.Add(h.Trim()) Next End If While Not parser.EndOfData Dim fields parser.ReadFields() 列数对不上就跳过避免整批导入失败 If fields.Length dt.Columns.Count Then dt.Rows.Add(fields) End If End While End Using Return dt End Function逻辑说明TextFieldParser按行推进HasFieldsEnclosedInQuotes True让它把双引号内的逗号当普通字符这是Split做不到的。先把表头读出来建DataTable的列后续每行按列数校验再Rows.Add这样脏行不会污染整批数据。参数说明Encoding.UTF8要按实际文件改。国内很多系统导出的是 GBK/GB2312用 UTF8 读会得到乱码此时改成System.Text.Encoding.GetEncoding(GB2312)。注意 .NET Core 默认不带 GB2312 编码需要先注册CodePagesEncodingProvider否则抛ArgumentException。注意如果 CSV 带 BOMUTF8 读取时第一列列名可能带一个不可见字符\uFEFF导致后面 SQL 列名对不上。稳妥做法是建列时h.Trim().TrimStart(ChrW(HFEFF))。3.3 大文件不要一次性读进 DataTable上面写法把整个文件读进内存几万行没问题上百万行就会吃光内存。常见做法是流式分批每读 N 行就提交一次N 取 1000 到 5000 之间。这样内存占用恒定失败时也只丢最后一批。Const BatchSize As Integer 2000 Dim batch As New List(Of String())() While Not parser.EndOfData batch.Add(parser.ReadFields()) If batch.Count BatchSize Then FlushBatch(batch) 见下一章的批量写入 batch.Clear() End If End While If batch.Count 0 Then FlushBatch(batch)参数说明BatchSize不是越大越好。太大单次事务时间长、锁持有久、回滚代价高太小则网络往返次数多、整体慢。2000 是多数内网场景的平衡点可以按行宽和网络延迟微调。4. 批量写入 MySQL从逐条 INSERT 到 MySqlBulkCopy4.1 逐条 INSERT 为什么慢慢在哪最直观的写法是遍历DataTable每行拼一条INSERT INTO ... VALUES (...)然后ExecuteNonQuery。功能没问题但性能很差原因有三每条 SQL 都要一次网络往返每条都要服务端解析、优化、执行默认自动提交模式下每条都是一个事务磁盘刷写频繁。实测经验一万行数据逐条插入内网环境通常要十几秒到几十秒换成批量方式能压到一秒以内。差距主要来自往返次数和事务开销不是 MySQL 本身慢。4.2 参数化批量插入的正确写法先看参数化 多值 INSERT 的写法兼容性最好Public Sub FlushBatch(rows As List(Of String()), connStr As String) If rows.Count 0 Then Return Using conn As New MySqlConnection(connStr) conn.Open() Using tran conn.BeginTransaction() Dim sb As New Text.StringBuilder() sb.Append(INSERT INTO sales (order_no, customer, amount, order_date) VALUES ) Dim cmd As New MySqlCommand() cmd.Connection conn cmd.Transaction tran For i As Integer 0 To rows.Count - 1 If i 0 Then sb.Append(,) sb.AppendFormat((no{0},cu{0},am{0},dt{0}), i) cmd.Parameters.AddWithValue(no i, rows(i)(0)) cmd.Parameters.AddWithValue(cu i, rows(i)(1)) cmd.Parameters.AddWithValue(am i, Decimal.Parse(rows(i)(2))) cmd.Parameters.AddWithValue(dt i, DateTime.Parse(rows(i)(3))) Next cmd.CommandText sb.ToString() cmd.ExecuteNonQuery() tran.Commit() End Using End Using End Sub逻辑说明把一批行拼成一条多值INSERT所有值都用参数占位避免 SQL 注入和引号转义问题。整批放在一个事务里要么全成功要么全回滚保证一致性。参数说明AddWithValue会根据 .NET 类型推断 MySQL 类型Decimal对应DECIMALDateTime对应DATETIME。注意AddWithValue传字符串时如果列是VARCHAR(20)而值很长可能被静默截断严格场景应显式指定MySqlDbType和长度。另外单条 SQL 有max_allowed_packet限制默认 4MB 或 64MB批太大要拆。4.3 MySqlBulkCopy大数据量的快车道数据量上到几十万行多值 INSERT 也会吃力这时用MySqlBulkCopy它底层走的是LOAD DATA LOCAL INFILE协议吞吐量高一个数量级。Public Sub BulkImport(dt As DataTable, connStr As String) Using conn As New MySqlConnection(connStr) conn.Open() Dim bulk As New MySqlBulkCopy(conn) bulk.DestinationTableName sales 列映射DataTable 列名 - 目标表列名 bulk.ColumnMappings.Add(New MySqlBulkCopyColumnMapping(order_no, order_no)) bulk.ColumnMappings.Add(New MySqlBulkCopyColumnMapping(customer, customer)) bulk.ColumnMappings.Add(New MySqlBulkCopyColumnMapping(amount, amount)) bulk.ColumnMappings.Add(New MySqlBulkCopyColumnMapping(order_date, order_date)) bulk.WriteToServer(dt) End Using End Sub逻辑说明MySqlBulkCopy把DataTable序列化成 MySQL 的本地文件导入格式服务端直接解析省掉逐行 SQL 解析。列映射必须显式加否则按位置对应列顺序不一致就写错列。参数说明用这个方式连接字符串必须带AllowLoadLocalInfileTrue服务端也要确认local_infile变量为ONSHOW VARIABLES LIKE local_infile;。如果服务端禁用会报The used command is not allowed with this MySQL version。另外MySqlBulkCopy在MySql.Data里对DataTable的列类型有要求DateTime列建议先确保没有空值否则可能抛转换异常。提示MySqlBulkCopy不走事务语义导入中途失败会留下部分数据。稳妥做法是先导入临时表校验行数无误后再INSERT INTO ... SELECT换到正式表。4.4 建表时该注意的字段类型导入前表结构要提前建好几个容易踩的点金额用DECIMAL(12,2)不要用FLOAT浮点会有精度误差日期用DATETIME或DATECSV 里的字符串格式要能对上文本列长度留够VARCHAR(255)存不下的地址会被截断或报错。字符集统一utf8mb4排序规则用utf8mb4_general_ci或utf8mb4_0900_ai_ci8.0。5. 避坑与排查导入失败时先看这几处5.1 中文变问号或乱码现象导入后库里中文显示成???或乱码方块。原因连接字符串没写CharSetutf8mb4或者 CSV 文件本身是 GBK 而代码按 UTF8 读。解决连接串补上CharSetutf8mb4同时确认 CSV 编码GBK 文件用Encoding.GetEncoding(GB2312)读并在 .NET Core 里注册CodePagesEncodingProvider.Instance。5.2 认证失败 caching_sha2_password现象连接时报Authentication method caching_sha2_password not supported。原因MySQL 8.0 默认认证插件是caching_sha2_password老版本驱动不支持。解决升级MySql.Data到 8.x或把用户改成mysql_native_passwordALTER USER app_user% IDENTIFIED WITH mysql_native_password BY ...;。生产环境优先升级驱动改认证插件是下策。5.3 批量导入报 max_allowed_packet 超限现象多值 INSERT 跑到一半报Packet for query is too large。原因单条 SQL 文本超过服务端max_allowed_packet。解决调小BatchSize或让 DBA 把max_allowed_packet调到 64M。注意这个参数是服务端和客户端都要够大客户端侧由驱动控制。5.4 日期格式解析异常现象DateTime.Parse抛FormatException。原因CSV 里日期是2024/01/05或05-01-2024这类非标准格式受当前区域设置影响。解决用DateTime.ParseExact(s, yyyy/MM/dd, CultureInfo.InvariantCulture)显式指定格式别依赖系统区域。5.5 导入后行数对不上现象CSV 明明一万行库里只有九千多。原因多半是空行、列数不匹配的行被静默跳过或者主键冲突被INSERT IGNORE吞掉。解决读 CSV 时统计跳过行数并记日志导入前先SELECT COUNT(*)对账主键冲突要么提前去重要么用ON DUPLICATE KEY UPDATE明确处理。6. 让这套管道更耐用的两个进阶技巧第一个技巧是给导入加「预校验 临时表」两段式。正式导入前先把 CSV 读进DataTable做一轮校验必填列是否为空、金额能否转Decimal、日期能否解析、主键是否重复。校验通过的行写进一张和正式表同结构的临时表sales_staging然后用一条INSERT INTO sales SELECT * FROM sales_staging WHERE NOT EXISTS (...)做去重合并。这样即使中途失败正式表也不受影响重跑时清空临时表即可。代价是多一次写入但换来的是可重入和可对账值。第二个技巧是把连接和批量参数做成配置项而不是硬编码。下面这张表是我在多个项目里沉淀下来的默认值可以直接抄参数默认值调整依据BatchSize2000行宽大或网络差调小到 500ConnectionTimeout15 秒跨机房调到 30DefaultCommandTimeout120 秒单批大时按比例放大CharSetutf8mb4固定别改SslMode内网 None / 公网 Required按网络环境AllowLoadLocalInfile仅 BulkCopy 时 True用完即关验证方法很简单拿一份一万行的样本 CSV分别用逐条 INSERT、多值 INSERT、MySqlBulkCopy 跑一遍记录耗时和内存峰值再故意在中间插一行坏数据看三种方式各自怎么失败、能不能重入。跑完这一轮你对这套管道的边界就有数了。我自己踩过最深的一次坑是图省事在连接串里全局开了AllowLoadLocalInfileTrue结果那台机器上任何能连库的进程都能读本地文件安全审计直接亮了红灯。后来改成只在 BulkCopy 那个连接上临时开用完立刻释放。做数据导入这种活儿性能可以慢慢调安全边界一旦松了就是后悔药都买不到。希望帮到你。本文还有配套的精品资源点击获取