开发邮箱注册校验功能触发There is no row at position 0错误,无法处理空查询结果
问题根因
这套代码的错误点非常明确,直接触发报错的原因和逻辑错位的问题分别是:
- 越界访问空集:代码完全没有判断查询结果有没有返回行,就强行去取
Rows[0]里的UserId值。当待注册邮箱在库里没有匹配记录时,整个表的行集合是空的,自然会抛出“There is no row at position 0”的索引越界错误。 - 业务判断逻辑完全错位:你本来要判断的是“查询返回的匹配行数是不是大于0”,结果代码写的是“把第一行的UserId值转成整数来比较大小”,就算没触发越界,这套逻辑也和你的业务需求完全不搭——碰到UserId为0的老数据场景,哪怕邮箱已经被注册了,也会误判成可正常注册。
- 附带SQL注入安全隐患:直接把用户输入的邮箱值拼进SQL语句里,存在明显的注入风险,攻击者可以通过构造特殊的邮箱值绕过校验。
修复方式
完全贴合你的原始业务逻辑调整,不需要读取单行的字段值,直接用返回行数做判断即可,同时补上安全防护:
- 拿到数据集后优先读取
Rows.Count属性获取匹配的记录总数,绝不在行数为0的时候尝试访问具体行的内容 - 按照计数结果分支判断:计数大于0说明邮箱已被占用,返回注册失败;计数为0说明邮箱可用,返回注册通过
- 把字符串拼接的SQL改成参数化查询,彻底规避注入风险
修复后的参考代码:
{ // 参数化查询替代字符串拼接,从根源避免SQL注入 String sql = "SELECT UserId FROM Users WHERE EmailAddress = @EmailAddress"; // 传入参数时由数据库组件自动处理特殊字符转义 DataSet mydata = dbConnect.GetDataSet(sql, new[] { new SqlParameter("@EmailAddress", emailaddress) }); // 直接取匹配行数做判断,不需要访问具体行的内容 int matchedCount = mydata.Tables[0].Rows.Count; if (matchedCount > 0) { return false; } else { return true; } }
注意:如果你的现有数据库连接封装不支持参数传参,至少要对用户输入的邮箱值做单引号等SQL特殊字符的转义,绝不能直接把用户输入拼进SQL字符串里执行。
内容的提问来源于stack exchange,提问作者Steven Polka
相关产品推荐
相关产品推荐

