C# WinForm报错:已有打开的DataReader关联命令,需先关闭
问题分析与解决:同一数据库连接下DataReader未关闭导致的错误
错误提示:"There is already an open DataReader associated with this Command which must be closed first"
原代码
MySqlConnection cn = conectar.fazer_conexao(); MySqlCommand cmd = new MySqlCommand(); cmd.Connection = cn; try { cn.Open(); if (txt_codigo.Text == "") { cmd.CommandText = "Insert into operacoes (nome_cliente, codigo_cliente, data_locacao) VALUES ('" + cmb_cliente.Text + "','" + codigo_cliente.Text + "','" + Convert.ToDateTime(mask_dl.Text).ToString("yyyy/MM/dd") + "')"; } cmd.CommandText = "SELECT 1544758"; MySqlDataReader read = cmd.ExecuteReader(); read.Read(); int id = Convert.ToInt32(cmd.ExecuteScalar()); for (int i = 0; i <= grid_jogos.RowCount - 1; i++) { if (Convert.ToBoolean(grid_jogos.Rows[i].Cells["select"].Value)) { string jogos = grid_jogos.Rows[i].Cells[1].Value.ToString(); cmd.CommandText = "Insert into itens (codigo_operacao, codigo_jogos) values ('" + id + "','" + jogos + "')"; } } cmd.ExecuteNonQuery(); cn.Close(); }
错误原因
- 未关闭DataReader就复用Command:创建
MySqlDataReader后,没有调用read.Close()或用using包裹,就直接通过同一个cmd对象执行ExecuteScalar(),同一个Command不能同时关联打开的DataReader执行其他操作,这是报错的直接原因。 - 第一个Insert命令仅设置了
CommandText,未执行就被SELECT语句覆盖,逻辑无效。 - 循环中仅更新
CommandText,最后只执行一次ExecuteNonQuery(),只会插入最后一个选中的行,前面的操作全部被覆盖。 - 直接拼接字符串构造SQL,存在严重SQL注入风险。
修正方案
- 不需要DataReader的场景直接用
ExecuteScalar()获取值,避免创建冗余的DataReader。 - 条件满足时执行第一个Insert命令。
- 循环中构造Insert命令后立即执行,避免覆盖操作。
- 使用
using语句自动释放Connection、Command等资源,无需手动关闭。 - 改用参数化查询,杜绝SQL注入。
修正后的代码
// using自动管理连接资源,无需手动关闭 using (MySqlConnection cn = conectar.fazer_conexao()) { cn.Open(); int id = 1544758; // 固定值直接赋值,无需额外查询 // 执行operacoes表插入(如果条件满足) if (string.IsNullOrEmpty(txt_codigo.Text)) { string insertOperacoesSql = "Insert into operacoes (nome_cliente, codigo_cliente, data_locacao) VALUES (@nome, @codigo, @data)"; using (MySqlCommand cmdOperacoes = new MySqlCommand(insertOperacoesSql, cn)) { cmdOperacoes.Parameters.AddWithValue("@nome", cmb_cliente.Text); cmdOperacoes.Parameters.AddWithValue("@codigo", codigo_cliente.Text); cmdOperacoes.Parameters.AddWithValue("@data", Convert.ToDateTime(mask_dl.Text)); cmdOperacoes.ExecuteNonQuery(); } } // 循环插入选中的itens数据 string insertItensSql = "Insert into itens (codigo_operacao, codigo_jogos) values (@operacaoId, @jogoCodigo)"; foreach (DataGridViewRow row in grid_jogos.Rows) { if (row.IsNewRow) continue; // 跳过表格自动生成的新行 if (Convert.ToBoolean(row.Cells["select"].Value)) { string jogoCodigo = row.Cells[1].Value.ToString(); using (MySqlCommand cmdItens = new MySqlCommand(insertItensSql, cn)) { cmdItens.Parameters.AddWithValue("@operacaoId", id); cmdItens.Parameters.AddWithValue("@jogoCodigo", jogoCodigo); cmdItens.ExecuteNonQuery(); } } } }
补充说明
同一数据库连接下可以执行多个操作,但需注意:
- 同一个Command对象不能同时关联打开的DataReader,必须先关闭DataReader再复用。
- 推荐为不同的SQL操作创建独立的Command对象,避免覆盖
CommandText导致逻辑错误。 - 参数化查询是必须的,绝不能直接拼接用户输入到SQL语句中。
内容的提问来源于stack exchange,提问作者user20990958
相关产品推荐
相关产品推荐

