ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

VB.NET 连 MySQL 导入 CSV 实战:连接字符串、批量插入与避坑指南

VB.NET 连 MySQL 导入 CSV 实战:连接字符串、批量插入与避坑指南 简介这份资源是面向VB.NET初学者与数据处理开发者的实战示例包聚焦在.NET环境下连接MySQL数据库并批量导入CSV文件这一常见需求适合需要完成数据迁移、报表入库或后台数据整理任务的开发者参考。压缩包共29个文件约75KB以vb源码文件为主辅以vbproj项目文件、sln解决方案、resx与resources资源文件、exe与dll编译产物及xml配置等构成一个可直接打开运行的完整工程。目前已有192人学习下载。示例围绕MySqlConnection连接字符串配置、TextFieldParser解析CSV、MySqlCommand执行INSERT语句、Try...Catch异常捕获、事务与批处理优化、连接释放等环节展开读者可据此掌握从文件读取到数据库落地的完整链路并借鉴其中的错误处理与性能优化思路快速套用到自己的数据导入场景中。1. 从一份 VB.NET 连 MySQL 导 CSV 的压缩包说起手上拿到一个叫VB.NET Connect MySQL and Import CSV file.zip的包解压出来是WindowsApplication1目录里面躺着.sln、.suo和项目文件。这不是什么新框架也不是什么高深架构就是一份典型的 VB.NET WinForms 示例工程干一件事把 CSV 文件里的数据读出来塞进 MySQL 表里。听起来简单但真到生产环境里跑连接字符串怎么写、CSV 里的引号逗号怎么处理、批量插入怎么不把内存撑爆每一步都有翻车的可能。这份资源适合两类人一是刚接手 VB.NET 老项目、需要快速补上数据库导入能力的维护者二是想拿一个能跑通的最小闭环改吧改吧就用在自己数据处理脚本里的从业者。下面我按实际拆包和复现的顺序把这份资源里的技术点、参数配置和踩坑记录摊开讲。2. 环境准备与 MySQL 连接从驱动选型到连接字符串2.1 为什么是 MySql.Data 而不是别的驱动VB.NET 连 MySQL绕不开驱动选择。这份资源用的是MySql.Data.MySqlClient命名空间也就是 Oracle 官方那套 Connector/NET。常见做法是在项目里通过 NuGet 装MySql.Data包或者直接引用MySql.Data.dll。有人会问为什么不用MySqlConnector这个社区版答案很简单这份示例工程年代偏早.suo和.sln的结构一看就是 Visual Studio 2010 到 2015 之间的产物那时候官方驱动是默认选项兼容性最稳。如果你现在要把它迁到 .NET 6 以上MySqlConnector性能更好、异步支持更完整但那是另一条路这份资源里不涉及。装驱动这一步新手最容易卡在版本上。MySQL 8.0 默认用caching_sha2_password认证插件老版本的MySql.Data连上去会直接报Authentication method caching_sha2_password not supported。解决办法有两个要么把 NuGet 包升到 8.0.12 以上要么在 MySQL 里把用户认证方式改回mysql_native_password。我一般会选前者因为改认证方式属于治标不治本后面换环境还得再踩一次。2.2 连接字符串的每个参数都别瞎填连接字符串是这份资源里最值得逐字看的部分。典型写法长这样Dim connStr As String Server127.0.0.1;Port3306;Databasetestdb;Uidroot;Pwdyourpassword;CharSetutf8mb4;SslModenone;逐项拆开说。Server填 IP 或主机名本地就是127.0.0.1或localhost注意localhost在某些驱动版本下会走命名管道而不是 TCP如果 MySQL 没开命名管道就会连不上所以生产环境我习惯直接写 IP。Port默认 3306改过端口的一定要显式写出来。Database是目标库名不写也能连上但后面执行 SQL 时还得USE不如一次写清。Uid和Pwd是账号密码别硬编码在代码里这份示例为了演示方便直接写在字符串里实际项目应该走配置文件或环境变量。CharSet这个参数特别关键。CSV 里如果有中文而连接字符串不指定utf8mb4导入后大概率是乱码。utf8mb4和utf8的区别在于前者支持完整的 Unicode 字符包括 emojiMySQL 8.0 之后默认就是utf8mb4但老库可能还是utf8写代码时统一用utf8mb4最省心。SslModenone是本地开发常用的跳过 SSL 握手省去证书配置的麻烦。如果数据库在远程且要求加密这个参数要改成Required并配好证书否则连接会被拒绝。2.3 打开连接与异常捕获的写法连接对象用完必须关这是铁律。示例里用的是Using块这是 VB.NET 里最稳妥的写法Try Using conn As New MySqlConnection(connStr) conn.Open() 后续操作 End Using Catch ex As MySqlException MessageBox.Show(数据库连接失败 ex.Message) Catch ex As Exception MessageBox.Show(发生未知错误 ex.Message) End TryUsing块的好处是无论中间是否抛异常退出块时都会自动调用Dispose()等价于手动Close()加Dispose()。MySqlException单独捕获是为了区分数据库层面的错误比如账号密码错、库不存在、网络不通这些错误的Number属性有具体错误码方便做针对性提示。外层再包一个通用Exception捕获防止文件读取之类的非数据库异常漏掉。注意Open()方法本身不返回值连接失败会直接抛异常所以不要写成If conn.Open() Then这种判断。3. CSV 解析与数据导入TextFieldParser 与批量插入3.1 用 TextFieldParser 而不是 SplitCSV 看着简单用String.Split(,)一行行切似乎也能跑但遇到字段里带逗号、带引号、带换行的情况立刻翻车。比如张三, 李四,25这一行按逗号切会切成三段完全错位。这份资源用的是Microsoft.VisualBasic.FileIO.TextFieldParser这是 VB.NET 自带的一个专门解析分隔文本的类能正确处理引号包围和转义。用法如下Using parser As New TextFieldParser(data.csv) parser.TextFieldType FieldType.Delimited parser.SetDelimiters(,) parser.HasFieldsEnclosedInQuotes True While Not parser.EndOfData Dim fields As String() parser.ReadFields() fields 就是一行里的各个字段 End While End UsingTextFieldType设为Delimited表示按分隔符解析SetDelimiters(,)指定逗号。HasFieldsEnclosedInQuotes必须设为True否则引号会被当成普通字符留在字段里。ReadFields()每次返回一个字符串数组长度就是列数。如果某行列数和预期不符ReadFields会抛MalformedLineException这时候可以用parser.ErrorLine拿到出错的那一行内容方便定位。3.2 逐行插入与批量插入的取舍最直观的导入方式是读一行插一行Dim sql As String INSERT INTO users (name, age, email) VALUES (name, age, email) Using cmd As New MySqlCommand(sql, conn) cmd.Parameters.Add(name, MySqlDbType.VarChar) cmd.Parameters.Add(age, MySqlDbType.Int32) cmd.Parameters.Add(email, MySqlDbType.VarChar) While Not parser.EndOfData Dim fields parser.ReadFields() cmd.Parameters(name).Value fields(0) cmd.Parameters(age).Value Integer.Parse(fields(1)) cmd.Parameters(email).Value fields(2) cmd.ExecuteNonQuery() End While End Using这种写法逻辑清晰但性能很差。每执行一次ExecuteNonQuery就是一次网络往返CSV 有一万行就是一万次往返本地库可能几秒远程库直接几分钟起步。优化手段是拼批量 INSERTDim batchSql As New StringBuilder() Dim batchCount As Integer 0 Dim batchSize As Integer 500 While Not parser.EndOfData Dim fields parser.ReadFields() batchSql.AppendFormat(({0},{1},{2}),, fields(0), fields(1), fields(2)) batchCount 1 If batchCount batchSize Then Dim finalSql As String INSERT INTO users (name, age, email) VALUES batchSql.ToString().TrimEnd(,c) Using cmd As New MySqlCommand(finalSql, conn) cmd.ExecuteNonQuery() End Using batchSql.Clear() batchCount 0 End If End WhilebatchSize设 500 到 1000 之间比较合适太小省不了往返太大可能撞上max_allowed_packet限制。MySQL 默认max_allowed_packet是 4MB 或 64MB取决于版本拼出来的 SQL 字符串别超过这个数。另外注意字符串拼接有 SQL 注入风险如果 CSV 内容不可信还是老老实实用参数化加事务牺牲一点性能换安全。3.3 事务与回滚别让半截数据留在表里批量导入最怕的是插到一半出错前面插进去的留在表里后面没插进去数据处于不一致状态。解决办法是把整个导入过程包在一个事务里Using transaction As MySqlTransaction conn.BeginTransaction() Try Using cmd As New MySqlCommand(sql, conn, transaction) 执行插入 End Using transaction.Commit() Catch ex As Exception transaction.Rollback() Throw End Try End UsingBeginTransaction开启事务MySqlCommand的构造函数第三个参数传入事务对象这样命令才在事务上下文里执行。全部成功后Commit任何一步抛异常就Rollback表里不会留下脏数据。注意事务会持有锁导入期间其他连接对同一张表的写操作会被阻塞所以大文件导入尽量安排在低峰期。4. 避坑与排查那些让导入失败或变慢的细节4.1 中文乱码现象、原因与解决现象是导入后数据库里中文显示成问号或乱码。原因通常有三层CSV 文件本身的编码不是 UTF-8连接字符串没指定CharSetutf8mb4或者表的字符集不是utf8mb4。解决要逐层排查。先用记事本或 VS Code 打开 CSV确认编码是 UTF-8 还是 GBK如果是 GBKTextFieldParser默认按系统编码读需要显式指定Encoding.GetEncoding(GB2312)。然后检查连接字符串有没有CharSetutf8mb4。最后用SHOW CREATE TABLE users看表的字符集不是utf8mb4的话用ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4改掉。4.2 日期和数字格式解析失败现象是Integer.Parse或DateTime.Parse抛FormatException。原因是 CSV 里的数字带了千分位逗号或者日期格式和系统区域设置不匹配。比如1,234会被 CSV 解析器切成两个字段2024/01/15在某些区域设置下解析不了。解决办法是解析前先做清洗数字字段去掉逗号再Parse日期用DateTime.ParseExact指定确切格式比如DateTime.ParseExact(fields(3), yyyy-MM-dd, Nothing)。如果 CSV 来源不可控用TryParse代替Parse解析失败就记日志跳过别让一行坏数据卡死整个导入。4.3 连接超时与命令超时现象是导入大文件时程序卡住过一会儿报Timeout expired。原因是默认连接超时 15 秒命令超时 30 秒批量插入数据量大时不够用。解决是在连接字符串里加Connection Timeout60在MySqlCommand对象上设CommandTimeout 300。但更根本的办法是减小batchSize把单次命令的执行时间压下来。另外如果 MySQL 服务器wait_timeout设得短长时间空闲的连接会被服务端断开导入过程中如果中间有停顿就可能撞上可以在连接字符串加Poolingtrue让连接池管理或者定期执行SELECT 1保活。4.4 主键冲突与重复导入现象是第二次跑导入脚本时报Duplicate entry。原因是表里有主键或唯一索引CSV 里的数据已经存在。解决方式取决于业务需求如果希望覆盖用INSERT INTO ... ON DUPLICATE KEY UPDATE如果希望跳过用INSERT IGNORE如果希望先清空再导导入前执行TRUNCATE TABLE。注意TRUNCATE不可回滚在事务里执行会隐式提交别把它和事务混用。我一般会在导入前加一个DELETE FROM users WHERE source_file data.csv按来源删除这样既避免冲突又保留其他来源的数据。4.5 大文件内存占用过高现象是导入几百 MB 的 CSV 时程序内存飙升甚至崩溃。原因是把整个文件读进内存再处理。TextFieldParser本身是流式读取的不会一次性加载全文件但如果代码里用了File.ReadAllLines就全读进来了。检查代码里有没有这类调用有的话改成StreamReader逐行读。另外批量插入时StringBuilder拼的 SQL 字符串也会占内存batchSize别设太大500 到 1000 足够。如果 CSV 有几十万行考虑分文件处理或者用LOAD DATA INFILE让 MySQL 自己读文件速度比客户端插入快一个数量级但要求文件在服务器本地或通过LOAD DATA LOCAL INFILE传输。5. 进阶技巧把导入逻辑抽成可复用模块并验证结果这份示例工程把连接、解析、插入都写在 Form 的按钮事件里跑通没问题但复用性差。实际项目里我习惯把它拆成三个独立函数GetConnectionString()返回连接字符串ParseCsv(filePath)返回DataTable或List(Of String())BulkInsert(conn, tableName, rows)负责批量写入。这样换一个 CSV 文件或换一张目标表只需要改参数不用动核心逻辑。验证导入结果是否完整别只看程序没报错。我一般会做三步核对第一步用SELECT COUNT(*) FROM users看总行数是否等于 CSV 行数减表头第二步抽查几条边界数据比如第一行、最后一行、字段里带逗号的那一行确认内容没串位第三步用CHECKSUM TABLE users或者对关键字段做SUM、MAX、MIN和 CSV 里用 Excel 算出来的值对比。如果对不上大概率是某几行解析时字段错位回去看MalformedLineException的日志。还有一个容易被忽略的点导入完成后显式关闭TextFieldParser和MySqlConnection。虽然Using块会自动处理但如果代码里用了全局变量持有连接对象GC 不会立刻回收连接池可能被占满。我习惯在Finally块里再补一次conn.Close()算是给自己上双保险。从那以后我每次做 CSV 导入都强制走一遍「先拿 100 行试跑核对字段映射和编码再全量导入」的流程省得几万行跑完才发现第三列对错了位。希望帮到你。本文还有配套的精品资源点击获取
返回列表