You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中MySqlDataReader.HasRows始终返回false,即使表中有数据

嘿,我来帮你排查这个问题!你遇到的HasRows一直返回false的情况,大概率是这几个原因导致的,咱们一步步来理清楚:

可能的问题根源

1. 重复调用Read()的小坑(但不是核心原因)

你代码里连续调用了两次reader.Read():

reader.Read(); 
Console.WriteLine(reader.Read()); 

第一次Read()会把阅读器的指针移到第一行数据(如果有的话),第二次Read()会尝试跳到下一行——如果你的查询结果只有一行,这步就会返回false。不过要说明的是,HasRows是判断结果集有没有行,和当前指针位置无关,所以这不是HasRows为false的根本原因,但会导致你后面读取reader["username"]的时候直接报错(因为指针已经跑到结果集外面了)。

2. SQL字符串拼接的致命问题(最可能的元凶)

你用字符串拼接写SQL的方式太危险了:

String sql = "SELECT * FROM user WHERE username='" + username + "' AND password='" + password + "'";

如果username或者加密后的password里有单引号、反斜杠这类特殊字符,直接就会把SQL语句搞坏。比如用户名是O'Neil的话,拼接后的SQL就变成了:

SELECT * FROM user WHERE username='O'Neil' AND password='xxx'

这明显是语法错误,数据库执行的时候直接返回空结果集,HasRows自然就是false了。而且这种写法还会招来SQL注入攻击,绝对不能在生产环境用!

3. MD5加密的一致性问题

你用md5Crypt(password)加密密码,但要确保数据库里存的密码和你加密后的结果完全匹配:

  • 检查加密算法的大小写:比如你加密后是小写,数据库里存的是大写?
  • 检查字符编码:加密时用的是UTF-8还是GBK?和数据库存储的编码要一致。
  • 检查空格:输入的密码前后有没有空格?加密后就会和数据库里的不一样。

解决办法,按优先级来

第一步:立刻换成参数化查询(必须做)

这能同时解决特殊字符和SQL注入的问题,代码改成这样:

password = md5Crypt(password); 
User u = null; 
// 用占位符代替直接拼接
String sql = "SELECT * FROM user WHERE username=@username AND password=@password"; 
try { 
    conn.Open(); 
    MySqlCommand cmd = new MySqlCommand(sql, conn); 
    // 给参数赋值
    cmd.Parameters.AddWithValue("@username", username);
    cmd.Parameters.AddWithValue("@password", password);
    MySqlDataReader reader = cmd.ExecuteReader(); 
    // 先判断HasRows再读取,或者直接用Read()的返回值
    if (reader.HasRows) { 
        reader.Read(); // 移到第一行数据
        u = new User(reader["username"].ToString(), reader["password"].ToString(), reader["name"].ToString(), reader["role"].ToString()); 
    } else { 
        u = null; 
    } 
    reader.Close(); // 别忘了关闭阅读器
    conn.Close(); 
} catch(Exception ex) {
    // 加上异常打印,方便排查问题
    Console.WriteLine("查询出错:" + ex.Message);
    // 确保连接关闭,避免资源泄漏
    if(conn.State == ConnectionState.Open) conn.Close();
}

第二步:排查MD5加密的匹配问题

  1. 在代码里打印加密后的password值,然后去数据库客户端(比如Navicat、MySQL Workbench)执行这条查询:
SELECT * FROM user WHERE username='你的测试用户名' AND password='打印出来的加密密码'

如果查不到数据,说明你的加密逻辑和数据库里存的密码不匹配,得调整加密代码。
2. 检查数据库的password字段类型:MD5加密后是32位字符,所以字段至少要设为VARCHAR(32),别设短了。

第三步:修复Read()的调用逻辑

别连续调用两次Read(),要么先判断HasRows再调用Read(),要么直接用Read()的返回值判断:

// 更简洁的写法:直接用Read()的返回值判断是否有数据
if(reader.Read()){
    u = new User(reader["username"].ToString(), reader["password"].ToString(), reader["name"].ToString(), reader["role"].ToString());
} else {
    u = null;
}

额外的调试小技巧

在代码里打印参数的值(比如加密后的密码、用户名),然后直接在数据库客户端执行查询,看能不能拿到结果。如果客户端能查到,代码里查不到,那就是代码里的参数传递或者加密的问题;如果客户端也查不到,那就是数据库里的数据确实不匹配,或者SQL逻辑有问题。

内容的提问来源于stack exchange,提问作者yuyu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:18:26