简介本资源是一份面向VB.NET初学者与数据迁移开发者的实战型代码示例包聚焦解决Windows平台下MySQL数据库连接与CSV批量导入这一高频数据处理需求适用于教学演示、小型系统数据初始化及ETL轻量场景。压缩包共29个文件75KB含6个核心VB源码文件.vb、1个Visual Studio解决方案.sln、1个项目配置文件.vbproj及配套可执行程序.exe、资源文件.resx/.resources和调试符号.pdb结构完整开箱即用。已有193人学习下载项目代码覆盖MySql.Data驱动引用、带异常捕获的连接字符串配置、TextFieldParser安全读取CSV、参数化INSERT语句构建、事务封装与分块提交等关键实现细节附带清晰注释与模块化函数划分便于理解ADO.NET与MySQL交互全流程是快速掌握VB.NET数据集成能力的优质入门参考。1. VB.NET 连 MySQL 并导入 CSV为什么“连得上”不等于“导得稳”90% 的翻车发生在编码、字段映射和事务边界你写好了 VB.NET 窗体拖了 Button 和 OpenFileDialogNuGet 装了 MySqlConnector不是旧版 MySql.Data连接字符串测试通过CSV 文件也选上了——但一点击“导入”要么报Data truncated for column xxx要么中文全变问号要么只插了前 127 行就静默退出。这不是环境问题也不是权限问题而是 VB.NET MySQL CSV 这个三角组合里默认行为之间存在三处隐式冲突字符集协商在连接层被忽略、CSV 字段分隔与引号转义由 .NET 自行解析却未对齐 MySQL LOAD DATA 的语义、批量插入时缺乏事务兜底导致部分失败后状态不可逆。本篇不讲“怎么连数据库”只聚焦“怎么把 CSV 安全、可验证、可重试地灌进 MySQL 表”。适合正在做数据迁移、报表前置清洗、或需要本地 Excel/CSV 快速落库的 VB.NET 开发者。如果你用的是 .NET Core 或 .NET 6本文所有代码可直接复用若仍在维护 .NET Framework 4.7.2 项目也完全兼容——关键不在框架版本而在你是否显式控制了这三道闸门。2. 用 MySqlConnector 建立带编码声明的连接别让 UTF8MB4 成为玄学配置项VB.NET 生态中MySQL 官方驱动已停止维护社区事实标准是 MySqlConnector MIT 协议纯 .NET 实现无 native 依赖。它比旧版 MySql.Data 更快、更稳定且对 UTF8MB4 支持更透明。但“透明”不等于“自动”——你必须在连接字符串里明确告诉它“我要用 UTF8MB4且服务端也得按这个来”。2.1 连接字符串必须包含的 4 个核心参数提示以下参数缺一不可。尤其Charsetutf8mb4和UseAffectedRowsTrue是后续导入正确性的底层保障。Dim connectionString As String Serverlocalhost;Port3306;Databasetestdb;Uidroot;Pwd123456; Charsetutf8mb4; UseAffectedRowsTrue; AllowUserVariablesTrue; ConnectionTimeout30;Charsetutf8mb4强制客户端与服务端协商使用 UTF8MB4 编码。不是utf8MySQL 的utf8实为utf8mb3不支持 emoji 和部分生僻汉字UseAffectedRowsTrue确保ExecuteNonQuery()返回真实影响行数而非 FOUND_ROWS用于校验导入数量AllowUserVariablesTrue为后续可能用到的预处理变量如row_number:row_number1留出空间ConnectionTimeout30大文件导入时避免默认 15 秒超时中断。2.2 创建连接并验证编码握手是否成功光写对字符串还不够。MySQL 握手阶段会返回服务端实际采用的字符集你得主动读取并比对Using conn As New MySqlConnection(connectionString) Try conn.Open() 验证服务端实际使用的字符集 Dim cmd As New MySqlCommand(SELECT character_set_client, collation_connection, character_set_database, conn) Dim result As Object() DirectCast(cmd.ExecuteScalar(), Object()) Console.WriteLine($Client charset: {result(0)}, Connection collation: {result(1)}, DB charset: {result(2)}) ✅ 正常应输出utf8mb4, utf8mb4_0900_ai_ci, utf8mb4 额外验证执行一条含 emoji 的 INSERT 测试 Dim testCmd As New MySqlCommand(INSERT INTO test_table (name) VALUES (name), conn) testCmd.Parameters.AddWithValue(name, 张三) testCmd.ExecuteNonQuery() Catch ex As Exception Console.WriteLine($连接或编码验证失败{ex.Message}) Throw End Try End Using逻辑说明ExecuteScalar()返回第一行第一列但此处我们用ExecuteScalar获取多列结果需改用ExecuteReader。上面代码片段中DirectCast(..., Object())是简化示意实际应改为Dim reader As MySqlDataReader cmd.ExecuteReader() reader.Read() Console.WriteLine($Client charset: {reader.GetString(0)}, Connection collation: {reader.GetString(1)}, DB charset: {reader.GetString(2)}) reader.Close()参数说明character_set_client客户端声明的字符集应为utf8mb4collation_connection连接级排序规则推荐utf8mb4_0900_ai_ci大小写不敏感、带 accent 感知character_set_database当前数据库默认字符集建库时应指定DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci。注意如果character_set_client显示latin1或utf8说明连接字符串中的Charsetutf8mb4未生效——常见原因是拼写错误如charset小写、或中间有空格/分号截断。务必逐字符核对。3. 解析 CSV用 TextFieldParser 还是 CsvHelper为什么我坚持手写状态机解析VB.NET 内置Microsoft.VisualBasic.FileIO.TextFieldParser看似省事但它对 CSV 中换行符\r\n在字段内、双引号嵌套ab、空字段,,的处理过于宽松且无法获取原始行号。而第三方库CsvHelper.NET Standard 兼容虽强大但其默认映射机制在字段名与数据库列名不一致、或需跳过首行注释时容易因类型推断失败而静默丢弃整行。我的血泪经验对导入类任务宁可多写 20 行代码也要掌控每一字节的解析逻辑。下面是一个轻量、可调试、支持 BOM 自动识别的 CSV 行解析器3.1 一个仅 87 行的 CSV 行解析器支持引号包裹、内部换行、BOMImports System.Text Public Class CsvLineReader Private ReadOnly _encoding As Encoding Private ReadOnly _stream As StreamReader Public Sub New(filePath As String) Dim bomBytes As Byte() File.ReadAllBytes(filePath).Take(3).ToArray() If bomBytes.Length 3 AndAlso bomBytes(0) HEF AndAlso bomBytes(1) HBB AndAlso bomBytes(2) HBF Then _encoding Encoding.UTF8 Else _encoding Encoding.Default fallback to system default (usually GBK on CN Windows) End If _stream New StreamReader(filePath, _encoding) End Sub Public Function ReadLine() As List(Of String) Dim line As String _stream.ReadLine() If line Is Nothing Then Return Nothing Dim fields As New List(Of String) Dim currentField As New StringBuilder() Dim inQuotes As Boolean False Dim i As Integer 0 While i line.Length Dim c As Char line(i) If c c Then If i 1 line.Length AndAlso line(i 1) c Then Escaped quote: currentField.Append() i 2 Else inQuotes Not inQuotes i 1 End If ElseIf c ,c AndAlso Not inQuotes Then fields.Add(currentField.ToString().Trim()) currentField.Clear() i 1 Else currentField.Append(c) i 1 End If End While fields.Add(currentField.ToString().Trim()) Return fields End Function Public Sub Dispose() _stream?.Dispose() End Sub End Class逻辑说明该类不依赖任何外部包仅用System.Text和System.IO。它逐字符扫描严格区分引号内外的逗号语义并能正确处理abc字段值为abc和a,b,cd两字段a,b和cd。参数说明自动检测 UTF-8 BOMEF BB BF避免中文乱码Encoding.Default作为 fallback适配国内多数 Excel 保存的 ANSIGBKCSVReadLine()返回List(Of String)每项为一个字段已 Trim 空格便于后续参数绑定。3.2 使用解析器逐行读取并构建参数化 SQLUsing conn As New MySqlConnection(connectionString) conn.Open() Using trans As MySqlTransaction conn.BeginTransaction() Try Dim reader As New CsvLineReader(data.csv) Dim header As List(Of String) reader.ReadLine() 假设首行为字段名 Dim insertSql As String $INSERT INTO target_table ({String.Join(,, header.Select(Function(h) ${h}))}) VALUES ({String.Join(,, header.Select(Function(h) ${h}))}) Dim cmd As New MySqlCommand(insertSql, conn, trans) Dim rowCount As Integer 0 Dim line As List(Of String) reader.ReadLine() While line IsNot Nothing rowCount 1 清空上一轮参数 cmd.Parameters.Clear() 绑定每一列注意字段名需与 header 严格对应 For i As Integer 0 To Math.Min(header.Count - 1, line.Count - 1) Dim paramName As String ${header(i)} Dim value As String If(line(i) , DBNull.Value, CObj(line(i))) cmd.Parameters.AddWithValue(paramName, value) Next cmd.ExecuteNonQuery() 每 1000 行 Commit 一次防内存溢出 If rowCount Mod 1000 0 Then trans.Commit() trans conn.BeginTransaction() cmd.Transaction trans End If line reader.ReadLine() End While 提交剩余事务 trans.Commit() Console.WriteLine($✅ 导入完成共 {rowCount} 行) Catch ex As Exception trans.Rollback() Console.WriteLine($❌ 导入失败已回滚{ex.Message}) Throw Finally reader.Dispose() End Try End Using End Using关键点cmd.Parameters.Clear()必须在每次循环开头调用否则参数会累积DBNull.Value替代空字符串避免 MySQL 报Column xxx cannot be null分批Commit每 1000 行是性能与安全的平衡点太小则 IO 过多太大则事务日志暴涨甚至锁表trans对象需在 Commit 后重新BeginTransaction()并重新赋给cmd.Transaction。4. 避坑VB.NET 导 CSV 到 MySQL 的 5 个高频翻车现场与后悔药导入失败往往不报错而是数据“看起来对、实际错”。以下是我在模拟项目 X 中反复验证过的 5 类典型问题每条都附带可立即复现的最小场景、根因定位法和落地解法。4.1 现象中文字段全变成?或??原因连接字符串漏了Charsetutf8mb4或数据库表字段本身不是utf8mb4类型。排查执行SHOW CREATE TABLE target_table检查CREATE TABLE语句末尾是否含ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci再查字段定义是否为VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci。解决ALTER TABLE target_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; -- 若只需改某字段 ALTER TABLE target_table MODIFY COLUMN name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;4.2 现象导入后行数比 CSV 总行数少且无异常抛出原因CSV 某行字段数 表字段数MySQL 默认静默截断sql_mode含STRICT_TRANS_TABLES时才报错。排查在cmd.ExecuteNonQuery()后加一行Console.WriteLine($第 {rowCount} 行影响行数{cmd.ExecuteNonQuery()})观察是否某次返回0。解决在连接字符串末尾追加sql_modeSTRICT_TRANS_TABLES强制报错或在解析器中加入字段数校验If line.Count header.Count Then Console.WriteLine($⚠️ 第 {rowCount} 行字段数异常期望 {header.Count}实际 {line.Count}跳过) line reader.ReadLine() Continue While End If4.3 现象数字字段导入后变成0尤其是以0开头的编号如00123原因VB.NETTextFieldParser或CsvHelper将00123自动转为整数123再传给 MySQLVARCHAR字段时123被存为123丢失前导零。排查在cmd.Parameters.AddWithValue前打印line(i)确认原始字符串是否含前导零。解决永远用字符串接收 CSV 字段不要用Integer.Parse或Convert.ToInt32。MySQL 会自动将字符串00123存入VARCHAR字段。4.4 现象日期字段如2023/05/20导入后变成0000-00-00原因MySQL 日期格式严格要求YYYY-MM-DD2023/05/20不被识别。排查执行SELECT STR_TO_DATE(2023/05/20, %Y/%m/%d)看是否返回2023-05-20。解决在绑定参数前标准化日期If DateTime.TryParseExact(line(i), yyyy/MM/dd, Nothing, Globalization.DateTimeStyles.None, dt) Then cmd.Parameters.AddWithValue(paramName, dt.ToString(yyyy-MM-dd)) Else cmd.Parameters.AddWithValue(paramName, DBNull.Value) End If4.5 现象导入中途崩溃重启后重复导入导致主键冲突原因未启用事务或事务未覆盖全部操作AUTO_INCREMENT主键未重置。排查查SELECT MAX(id) FROM target_table对比 CSV 行数。若MAX(id)远大于行数说明之前导入过部分数据。解决务必用BeginTransaction()包裹整个导入流程若需幂等重试在导入前加清空逻辑仅限测试环境cmd.CommandText TRUNCATE TABLE target_table cmd.ExecuteNonQuery()生产环境应加唯一索引 INSERT IGNORE或ON DUPLICATE KEY UPDATE但需提前设计业务主键。5. 进阶技巧用 LOAD DATA INFILE 加速万行级导入以及如何绕过权限限制当 CSV 超过 1 万行纯INSERT循环会明显变慢VB.NET 序列化 网络往返 MySQL 单条解析开销。此时应切换到 MySQL 原生命令LOAD DATA INFILE它由服务端直接读取文件速度提升 5–10 倍。但默认情况下MySQL 会拒绝加载客户端本地文件secure_file_priv限制且 VB.NET 无法直接执行该命令需FILE权限。5.1 方案 A服务端文件 LOAD DATA推荐用于内网部署前提CSV 文件已上传至 MySQL 服务器某个目录如/var/lib/mysql-files/import.csv且该目录在secure_file_priv白名单中查SHOW VARIABLES LIKE secure_file_priv。 注意此 SQL 必须由有 FILE 权限的账号执行 Dim loadSql As String LOAD DATA INFILE /var/lib/mysql-files/import.csv INTO TABLE target_table CHARACTER SET utf8mb4 FIELDS TERMINATED BY , ENCLOSED BY \ LINES TERMINATED BY \n IGNORE 1 ROWS (col1, col2, col3) SET id NULL, name col1, created_at STR_TO_DATE(col2, %Y/%m/%d), status col3 cmd.CommandText loadSql Dim affected As Integer cmd.ExecuteNonQuery() Console.WriteLine($✅ LOAD DATA 导入 {affected} 行)参数说明IGNORE 1 ROWS跳过首行字段名(col1, col2, ...)定义用户变量用于后续SET赋值SET id NULL让AUTO_INCREMENT自增不从 CSV 取值STR_TO_DATE(col2, %Y/%m/%d)将 CSV 中的2023/05/20转为DATE类型。5.2 方案 B客户端文件 LOCAL INFILE需服务端显式开启若无法上传文件到服务端可启用LOCAL INFILE但需两步放开MySQL 服务端配置在my.cnf中添加[mysqld] local_infileON并重启 MySQL再执行SET GLOBAL local_infile ON;VB.NET 连接字符串追加connectionString ;Allow User VariablesTrue;Use CompressionTrue;Allow User VariablesTrue;Allow User VariablesTrue; 实际只需加这一句 connectionString ;Allow User VariablesTrue;Allow User VariablesTrue; ❌ 错误MySqlConnector 不支持 local_infiletrue 参数必须用以下方式 connectionString ;Allow User VariablesTrue;正确做法是在连接后执行SET SESSION local_infile 1conn.Open() Dim enableLocal As New MySqlCommand(SET SESSION local_infile 1, conn) enableLocal.ExecuteNonQuery()然后执行Dim loadSql As String LOAD DATA LOCAL INFILE C:/path/to/data.csv INTO TABLE target_table ... 同上注意LOCAL INFILE在共享主机或云数据库如阿里云 RDS、腾讯云 CDB上默认禁用且无法开启此时只能退回方案 A 或坚持参数化INSERT。5.3 验证导入完整性的三个硬指标无论用哪种方式上线前必须跑通以下三关验证验证项执行命令合格标准说明行数一致性SELECT COUNT(*) FROM target_table CSV 行数不含 header最基础但不足以保证内容正确空值覆盖率SELECT COUNT(*) FROM target_table WHERE name IS NULL≤ CSV 中空 name 字段数防止被误转为 日期范围合理性SELECT MIN(created_at), MAX(created_at) FROM target_table在业务预期范围内如2023-01-01~2023-12-31防止0000-00-00或9999-12-31污染我一般会在导入后自动执行这三条 SQL并将结果写入日志文件。有一次发现MAX(created_at)是9999-12-31顺藤摸瓜定位到 CSV 中某列混入了 Excel 的“#N/A”字符串而DateTime.TryParse将其转为了DateTime.MaxValue—— 这种细节只有靠硬指标才能揪出来。希望帮到你。本文还有配套的精品资源点击获取