C#文本框TextChanged事件触发MySQL查询时出现内存访问违规求助
嘿,这个内存访问违规的问题我帮你拆解下,主要有几个坑你踩了,咱们一步步来解决:
问题根源分析
重复释放资源引发的内存异常
你在using块里手动调用了connect.Close()、read.Close()和read.Dispose(),但using语句的核心作用就是自动管理资源——当代码走出using块时,会自动调用这些资源的Dispose方法(包括关闭连接、释放阅读器)。手动重复释放会导致资源被多次清理,进而触发内存访问的异常。TextChanged高频触发的并发冲突
每输入一个字符,TextChanged就会触发一次。快速输入时,会同时发起多个数据库查询请求,而且这些请求都是同步执行的,会阻塞UI线程。更糟的是,多个请求的结果可能会同时尝试修改txtSearch.AutoCompleteCustomSource,导致UI控件的内部状态被并发修改,最终引发内存访问违规。
修复方案
咱们一步步调整代码:
移除手动释放资源的冗余代码
把connect.Close()、read.Close()、read.Dispose()全部删掉,让using块自动处理资源释放,这是它的本职工作。添加防抖逻辑,限制查询频率
用一个Timer实现防抖:当用户停止输入300ms(可根据需求调整)后,再执行数据库查询,避免频繁触发无效请求。异步执行数据库操作,避免阻塞UI
使用async/await异步执行数据库查询,这样UI线程不会被卡住,同时可以取消之前未完成的请求,防止旧结果覆盖新输入对应的补全数据。
修改后的完整代码示例
// 声明防抖用的Timer private System.Windows.Forms.Timer _debounceTimer; // 在窗体构造函数或者Load事件里初始化Timer public YourForm() { InitializeComponent(); _debounceTimer = new System.Windows.Forms.Timer(); _debounceTimer.Interval = 300; // 停止输入300ms后执行查询 _debounceTimer.Tick += DebounceTimer_Tick; } private void txtSearch_TextChanged(object sender, EventArgs e) { // 每次输入时重置Timer _debounceTimer.Stop(); if (txtSearch.TextLength > 0) { _debounceTimer.Start(); } else { // 清空补全源 txtSearch.AutoCompleteCustomSource.Clear(); } } private async void DebounceTimer_Tick(object sender, EventArgs e) { _debounceTimer.Stop(); // 停止Timer,避免重复触发 string searchText = txtSearch.Text; if (string.IsNullOrEmpty(searchText)) return; try { using (MySqlConnection connect = new MySqlConnection(cs)) { await connect.OpenAsync(); // 异步打开连接 using (var cmd = connect.CreateCommand()) { cmd.CommandText = "SELECT name FROM search WHERE name LIKE @sname"; cmd.Parameters.Add(new MySqlParameter("sname", "%" + searchText + "%")); using (MySqlDataReader read = await cmd.ExecuteReaderAsync()) // 异步执行查询 { AutoCompleteStringCollection collect = new AutoCompleteStringCollection(); while (await read.ReadAsync()) // 异步读取数据 { collect.Add(read.GetString(0)); } // await会自动回到UI线程,直接设置补全源即可 txtSearch.AutoCompleteCustomSource = collect; } } } } catch (Exception ex) { error(ex.Message, "Error"); } }
额外注意点
- 记得在窗体关闭时清理Timer:在
FormClosing事件里调用_debounceTimer.Dispose(),避免内存泄漏。 - 你已经用了参数化查询,这点做得很棒,有效避免了SQL注入风险。
这样调整后,既能避免频繁的数据库请求,又能正确管理资源,还不会阻塞UI线程,应该就能解决内存访问违规的问题了!
内容的提问来源于stack exchange,提问作者Emms

