使用@SqlResultSetMapping的JPA原生查询抛出SQL异常:找不到列'formula3_0_'
搞定JPA原生查询+@SqlResultSetMapping的
Column 'formula3_0_' not found异常 这个异常我之前也碰到过,本质是JPA(大多是Hibernate底层)找不到对应映射的列,尤其是那些自动生成的别名列,咱们一步步来排查解决:
先搞懂为啥会出现formula3_0_这种奇怪的列名
formula3_0_这类命名是Hibernate自动给没有显式指定别名的计算/聚合列生成的临时别名。比如你SQL里写了COUNT(*)、SUM(score)但没给别名,或者查询里的列和映射不匹配时,Hibernate就会自动生成这种别名,结果你的映射里没对应上,就抛出找不到列的异常。
结合你给出的代码片段,大概率是这几个情况:
- 你的原生查询返回了实体之外的额外列(比如统计数),但没给这些列加别名,也没在
@SqlResultSetMapping里用@ColumnResult映射它们。 - 你写的
@FieldResult里的字段名、列名和实际SQL返回的不匹配(比如代码里@FieldResult(name = "log...")截断了,可能是字段名写错或者列名没对齐)。 - 两个实体有同名字段(比如都叫
id),SQL里没区分别名,导致JPA混淆了列的归属。
针对性解决办法
1. 给SQL里的所有列(尤其是计算列)加明确别名
不管是实体字段还是额外的统计列,都别偷懒,给个清晰的别名。比如你的SQL如果是:
SELECT mi.id, mi.remote_addr, mi.user_email, el.log_id, COUNT(*) FROM marketing_info mi JOIN event_log el ON mi.id = el.marketing_id WHERE ...
赶紧给COUNT(*)加别名:COUNT(*) AS total_events,这样Hibernate就不会瞎生成formula3_0_这种别名了。
2. 补全@SqlResultSetMapping的映射
如果查询返回了实体之外的列,必须用@ColumnResult把它们加进映射里,同时检查实体字段的映射是否完整正确。比如:
@SqlResultSetMapping( name = "EventLogMarketingInfoMapping", entities = { @EntityResult( entityClass = MarketingInfo.class, fields = { @FieldResult(name = "id", column = "id"), @FieldResult(name = "remoteAddr", column = "remote_addr"), @FieldResult(name = "userEmail", column = "user_email") // 注意:这里name要和实体类的字段名完全一致,比如实体里是userEmail就别写user_email } ), @EntityResult( entityClass = EventLog.class, fields = { @FieldResult(name = "logId", column = "log_id"), // 把截断的部分补全,确保column和SQL里的列名/别名一致 @FieldResult(name = "createTime", column = "create_time") } ) }, columns = { // 这里放实体之外的额外列 @ColumnResult(name = "total_events") // 对应SQL里的别名 } )
敲黑板:实体类的字段名要和@FieldResult的name严格匹配,比如实体里是private String userEmail;,那name就必须是userEmail,不能写成数据库列名user_email(column属性才是对应数据库列名的)。
3. 解决实体间的列名冲突
如果两个实体有同名字段(比如都有id),SQL里一定要给它们加不同的别名区分:
SELECT mi.id AS marketing_id, el.id AS log_id, mi.remote_addr, ...
然后在映射里分别对应:
// MarketingInfo的id @FieldResult(name = "id", column = "marketing_id") // EventLog的id @FieldResult(name = "id", column = "log_id")
这样JPA就不会把两个id搞混,也就不会生成奇怪的自动别名了。
4. 验证步骤走一遍
- 先单独跑原生SQL,看看返回的列名列表,确保每个列都有明确别名,没有模糊的列名。
- 对比
@SqlResultSetMapping里的每一项,确保SQL里的每个列都有对应的@FieldResult或@ColumnResult。 - 检查实体类的字段名和
@FieldResult的name有没有拼写错误,大小写也要注意(有些数据库大小写敏感)。
内容的提问来源于stack exchange,提问作者Jamil Farooq
相关产品推荐
相关产品推荐

