SpringBoot JPA原生查询报Column 'id' not found错误如何解决
问题根因
报错核心原因是原生SQL查询返回的字段集,和JPA实体映射的要求不匹配:
- 你的
findByEmailId方法声明返回SessionHandling实体类型,但手写的原生SQL只查询了email单个字段,没有查询实体类必须的主键字段id(实体中id被@Id注解标注为主键,是JPA映射实体时的必填字段)。 - 当传入未注册的新邮箱时,SQL查询返回空结果集,JPA直接返回
null,不会执行实体映射逻辑,因此不会报错;当传入已存在的邮箱时,SQL返回了数据行,JPA尝试将结果集映射为SessionHandling对象时找不到id列,就会抛出Column 'id' not found的异常。 - 你写的
findByEmailIdAndPassword方法存在相同问题,仅查询了email和password字段,同样缺失主键id,后续调用时也会触发同类错误。
另外你当前在Controller层直接抛出通用Exception的写法,会让Spring把业务校验错误当成服务器内部错误,统一返回500状态码,不符合接口错误码的规范。
修复方案
三种方案任选其一即可:
方案1:补全原生SQL的查询字段
保留现有代码逻辑,只需要把两个查询方法的SQL字段补全,至少包含主键id,如果需要完整映射实体就查询所有实体对应字段:
@Repository @Transactional public interface SessionHandlingRepository extends JpaRepository<SessionHandling, Integer>{ @Query(value="Select id, name, email, password, cpassword from session_handling where email= :email",nativeQuery =true) public SessionHandling findByEmailId(@Param("email")String email); @Query(value="Select id, name, email, password, cpassword from session_handling where email= :email AND password= :password",nativeQuery =true) public SessionHandling findByEmailIdAndPassword(@Param("email")String email, @Param("password")String password); }
该方案改动最小,不需要调整其他层的代码。
方案2:使用JPA派生查询替代手写原生SQL
你的两个查询都是简单的等值条件匹配,完全不需要手写原生SQL,直接按照JPA方法命名规则定义方法,框架会自动生成正确的查询SQL,从根源上避免字段漏写的问题:
@Repository @Transactional public interface SessionHandlingRepository extends JpaRepository<SessionHandling, Integer>{ // 框架自动生成按email查询的SQL,返回匹配的实体对象 SessionHandling findByEmail(String email); SessionHandling findByEmailAndPassword(String email, String password); }
注意同步修改Service层调用的方法名即可。
方案3:优化校验逻辑,仅查询判断是否存在
邮箱重复校验的逻辑本质只需要确认对应邮箱是否已有记录,不需要查询完整的用户实体,这种场景直接返回计数结果效率更高,也不会出现实体映射错误:
// Repository层 @Query(value="Select count(1) from session_handling where email= :email",nativeQuery =true) long countByEmail(@Param("email")String email);
同步调整Controller层的判断逻辑:
@PostMapping("/register") public SessionHandling addUser(@RequestBody SessionHandling registration) throws Exception { String tempEmailId = registration.getEmail(); if(tempEmailId != null && !"".equals(tempEmailId)) { long emailCount = service.countByEmail(tempEmailId); if(emailCount > 0) { throw new Exception("user with " +tempEmailId+ " already exist"); } } return service.addUser(registration); }
额外优化建议
建议不要直接抛出通用Exception,可以自定义如EmailAlreadyExistedException的业务异常类,搭配@RestControllerAdvice实现全局异常处理,给邮箱重复的场景返回400 Bad Request或者409 Conflict状态码,方便前端精准识别错误类型做对应提示。
内容的提问来源于stack exchange,提问作者Harshit Toxia
相关产品推荐
相关产品推荐

