重复调用MySqlReader报错:Invalid attempt to access a field before calling Read()
问题分析与修复
错误原因
你遇到的Invalid attempt to access a field before calling Read()错误,核心不是复用旧的MySqlReader实例——每次调用getAccount都会创建新的reader,真正问题出在:
- 没判断
reader.Read()的返回值:如果查询不到对应login的账户,Read()会返回false,这时直接访问reader字段就会触发错误。 - SQL语句用字符串拼接,存在严重SQL注入风险,要是
login包含单引号这类特殊字符,还会直接导致SQL语法错误。 - 手动调用
reader.Close()和connection.Close()完全多余,using块会自动释放这些资源。
修复后的代码
public static Account getAccount(string login) { using (MySqlConnection connection = new MySqlConnection(CONNECT_STR_ACCOUNTS)) { connection.Open(); // 用参数化查询替代字符串拼接,避免注入和语法错误 using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM accounts WHERE " + COLUMN_LOGIN + " = @login", connection)) { cmd.Parameters.AddWithValue("@login", login); using (MySqlDataReader reader = cmd.ExecuteReader()) { // 先确认是否读取到有效数据 if (reader.Read()) { return new Account( reader[NUM_COL_FIRST_NAME].ToString(), reader[NUM_COL_LAST_NAME].ToString(), reader[NUM_COL_LOGIN].ToString(), reader[NUM_COL_PASSWORD].ToString(), Convert.ToInt32(reader[NUM_COL_LEVEL_ACCSES]), reader[NUM_COLUMN_BIRHTDAY].ToString() ); } // 未找到对应账户时返回null,也可根据业务需求抛出自定义异常 return null; } } } }
关键修复点
- 参数化查询:用
@login参数代替字符串拼接,彻底解决SQL注入和特殊字符引发的语法问题。 - 校验Read()结果:只有当
reader.Read()返回true(查到数据)时,才去读取字段内容。 - using包裹资源:给MySqlCommand和MySqlDataReader也加上
using,确保资源自动释放,无需手动Close()。 - 移除多余的
connection.Close():using块结束时会自动关闭并释放连接。
内容的提问来源于stack exchange,提问作者Ivan Kuznetsov
相关产品推荐
相关产品推荐

