Spring Data JPA原生查询报SQLGrammarException:按ID查指定列失败
问题场景
刚接触Spring Data JPA,在Spring Boot项目中编写原生Query,希望根据ID获取对应first_name(数据库列名为first_name)的数据。该SQL语句在MySQL数据库中能正常执行,但代码运行时抛出org.springframework.dao.InvalidDataAccessResourceUsageException,嵌套异常为org.hibernate.exception.SQLGrammarException,提示'Column 'id' not found'。
相关代码
实体类(EmployeeEntity)
package com.jpademo.demo.entity; import lombok.*; import javax.persistence.*; @Data @NoArgsConstructor @Setter @Getter @ToString @Entity @Table(name = "TBL_EMPLOYEES") public class EmployeeEntity { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private long id; @Column(name = "first_name") private String firstName; @Column(name = "last_name") private String lastName; @Column(name = "email", nullable = false, length = 200) private String email; public EmployeeEntity(String firstName, String lastName, String email) { this.firstName = firstName; this.lastName = lastName; this.email = email; } }
仓库接口(EmployeeRepository)
package com.jpademo.demo.repository; import com.jpademo.demo.entity.EmployeeEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.Optional; @Repository public interface EmployeeRepository extends JpaRepository <EmployeeEntity, Long>{ // 派生查询 Optional<EmployeeEntity> findByFirstName(String firstName); // 原生查询 @Query(nativeQuery=true, value="select * from TBL_EMPLOYEES where id=:id" ) Optional<EmployeeEntity> findDataById(@Param("id") long id); @Query(nativeQuery=true, value="select first_name from TBL_EMPLOYEES where id=:id" ) Optional<EmployeeEntity> findFirstNameById(@Param("id") long id); @Query(nativeQuery=true, value="select email from TBL_EMPLOYEES where id=:id" ) Optional<EmployeeEntity> findEmailById(@Param("id") long id); }
调用测试方法
@Test void nativeQuery2(){ System.out.println("******* TEST ********"); Optional<EmployeeEntity> response = employeeRepository.findFirstNameById(1L); if(response.isEmpty()) { System.out.println("********* No Record Found with this Id *********"); }else{ System.out.println(response.toString()); } }
堆栈信息
******* TEST ******** Hibernate: select first_name from TBL_EMPLOYEES where id=? 2023-10-04 11:54:54.964 WARN 1732 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: S0022 2023-10-04 11:54:54.964 ERROR 1732 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Column 'id' not found. org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute query; SQL [select first_name from TBL_EMPLOYEES where id=?]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query
表结构说明
数据库表TBL_EMPLOYEES包含主键列(疑似名为EMPLOYEE_ID)、first_name、last_name、email等列。
原因分析与解决方法
核心原因1:查询结果无法映射到实体类
findFirstNameById方法返回类型是Optional<EmployeeEntity>,但原生查询只返回了first_name单个字段。Hibernate映射实体类时,必须找到@Id标注的id字段对应列值,而查询结果中没有id列,因此抛出Column 'id' not found错误。
解决方法:
如果仅需获取first_name,直接修改方法返回类型为Optional<String>,无需映射到完整实体:
@Query(nativeQuery=true, value="select first_name from TBL_EMPLOYEES where id=:id" ) Optional<String> findFirstNameById(@Param("id") long id);
调用时直接处理字符串结果:
@Test void nativeQuery2(){ System.out.println("******* TEST ********"); Optional<String> response = employeeRepository.findFirstNameById(1L); if(response.isEmpty()) { System.out.println("********* No Record Found with this Id *********"); }else{ System.out.println("First Name: " + response.get()); } }
核心原因2:实体类字段与数据库列名不匹配
从表结构推测,数据库主键列可能不是id,而是EMPLOYEE_ID(或其他名称)。实体类id字段未指定@Column注解,JPA默认使用字段名id作为数据库列名,导致SQL中where id=:id找不到对应列。
解决方法:
- 修改实体类
id字段,添加@Column注解指定数据库实际列名:
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @Column(name = "EMPLOYEE_ID") // 替换为数据库实际主键列名 private long id;
- 同步修改原生查询的where条件,使用数据库实际列名:
@Query(nativeQuery=true, value="select first_name from TBL_EMPLOYEES where EMPLOYEE_ID=:id" ) Optional<String> findFirstNameById(@Param("id") long id);
额外建议
- 编写原生查询时,确保SQL列名与数据库实际列名完全一致;
- 若只需获取单个或部分字段,优先使用对应数据类型作为返回值,避免强制映射到完整实体类;
- 开启
spring.jpa.show-sql=true配置,查看Hibernate生成的SQL,方便排查字段匹配问题。
内容的提问来源于stack exchange,提问作者Ravi Reddy

