登录接口异常:selectOne() 返回多条结果(Expected one result but found:2)
你现在遇到的异常是Expected one result (or null) to be returned by selectOne(), but found: 2,核心原因是:你用selectOne()方法查询用户(admin),但数据库中符合条件的sys_user记录有2条,而selectOne()要求只能返回0条或1条结果。
结合你之前的登录日志(SQL:SELECT user_name, status FROM sys_user WHERE del_flag = '0' AND (user_name = 'admin')),下面一步步讲清楚原因、排查方法和解决方案。
一、先理解异常本质
selectOne()是 MyBatis 提供的方法,设计初衷是:
- 期望查询结果最多1条(0条返回null,1条返回实体);
- 如果返回多条(比如2条),直接抛出上述异常。
你的场景中,数据库里sys_user表存在2条user_name='admin'且del_flag='0'的记录,触发了这个异常。
二、第一步:排查数据库数据(快速定位)
先执行SQL确认重复数据,这是最直接的方式:
-- 执行以下SQL,查看有多少条admin用户记录SELECTid,user_name,status,del_flagFROMsys_userWHEREdel_flag='0'ANDuser_name='admin';执行后会看到结果行数为2,甚至更多——这就是异常的根源。
为什么会出现重复的admin用户?
常见原因:
- 手动插入时重复创建了admin账号;
- 代码中新增用户逻辑有BUG,重复插入;
user_name字段未设置唯一索引,导致重复插入。
三、第二步:解决方案(分「紧急修复」和「长期预防」)
1. 紧急修复:清理重复数据(立即解决异常)
先删除/禁用重复的admin记录,保留一条有效记录:
-- 1. 查看重复记录的ID(假设ID为1和2)SELECTid,user_nameFROMsys_userWHEREuser_name='admin'ANDdel_flag='0';-- 2. 禁用重复记录(推荐,不直接删除,保留数据)UPDATEsys_userSETdel_flag='1'WHEREid=2;-- 禁用ID=2的重复记录-- 或直接删除(谨慎!备份后操作)DELETEFROMsys_userWHEREid=2;执行后重新测试登录接口,异常会立即消失。
2. 代码层面优化(避免后续触发)
即使清理了重复数据,也建议优化代码,增加容错性:
(1)替换selectOne()为selectList(),手动处理结果
// 原错误代码(用selectOne,易触发异常)SysUseruser=sysUserMapper.selectOne(newQueryWrapper<SysUser>().eq("user_name","admin").eq("del_flag","0"));// 优化后代码(用selectList,手动处理多条结果)List<SysUser>userList=sysUserMapper.selectList(newQueryWrapper<SysUser>().eq("user_name","admin").eq("del_flag","0"));SysUseruser=null;if(CollectionUtils.isEmpty(userList)){// 无用户,返回账号不存在log.warn("用户admin不存在");}elseif(userList.size()>1){// 多条用户,记录日志并抛出明确异常(或取第一条)log.error("发现多条admin用户记录,数量:{}",userList.size());// 可选:取第一条有效记录,或抛出业务异常user=userList.get(0);// 或抛出异常:throw new BusinessException("账号异常,请联系管理员");}else{// 正常情况,取唯一记录user=userList.get(0);}(2)给user_name加唯一索引(从根上防止重复)
在数据库中给sys_user.user_name添加唯一索引,避免重复插入:
-- 给user_name添加唯一索引(包含del_flag,避免禁用后仍无法新增)ALTERTABLEsys_userADDUNIQUEINDEXidx_user_name_del_flag(user_name,del_flag);⚠️ 说明:联合索引(user_name, del_flag)意味着「同一用户名+同一删除状态」只能有一条记录,既防止重复有效用户,又允许禁用后重新创建同名用户。
3. 补充:MyBatis-Plus 场景的优化
如果你用的是 MyBatis-Plus,也可以用getOne()方法并指定容错策略:
// MyBatis-Plus的getOne方法,支持指定当多条结果时取第一条SysUseruser=sysUserService.getOne(newQueryWrapper<SysUser>().eq("user_name","admin").eq("del_flag","0"),false// false表示多条结果时取第一条,true表示抛出异常(默认));四、总结(核心要点)
- 异常根因:
selectOne()查询admin用户返回2条记录,违反其“最多1条”的设计规则; - 紧急修复:清理数据库中重复的admin记录(禁用/删除);
- 长期预防:
- 代码层面:用
selectList()替代selectOne(),手动处理多条结果; - 数据库层面:给
user_name加唯一索引,防止重复插入;
- 代码层面:用
- 关键提醒:用户名字段是核心唯一标识,必须通过唯一索引保障唯一性,避免类似问题复发。
如果清理数据后仍有异常,可贴出sys_user表的admin记录查询结果,我帮你进一步分析!