You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Native SQL在Spring Boot与SQL Workbench执行结果不一致问题排查

问题原因及解决方案

核心原因

你的ExperimentDetails类用@Id标注了externalId字段,但SQL查询结果中所有记录的external_id(对应externalId)都是同一个值(查询条件明确指定了ce.external_id = 'someExperimentID')。

JPA的EntityManager会通过@Id字段识别唯一实体,当所有结果行的Id值相同时,它会认为这些都是同一个实体,只会创建第一个实体对象并缓存,后续行直接复用该缓存对象,最终导致所有记录显示为第一条的数据内容。


解决方案

方案一:移除JPA实体注解(推荐,符合你原本的需求)

既然你不想用@Entity注解,直接将ExperimentDetails作为普通DTO类使用,通过调整SQL列别名或配置命名策略实现字段映射:

  1. 修改POJO类:移除@Entity和@Id注解
package com.pdb.testdbconn.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExperimentDetails {
    private String externalId;
    private String isid;
    private String name;
    private String controlledStatus;
    private String jurisdictionName;
    private String resultComments;
    private String codeName;
    private String corporateId;
}
  1. 调整SQL查询:给列添加别名,匹配POJO的驼峰字段名
@Query(value = "Select ce.external_id as externalId, ce.isid as isid, ji.name as name, ji.controlled_status as controlledStatus, " +
    "ji.jurisdiction_name as jurisdictionName, ji.result_comments as resultComments," +
    "ji.code_name as codeName, s.corporate_id as corporateId " +
    "from cs_jurisdiction_information ji " +
    "Join substance s on ji.substance_id = s.id " +
    "Join controlled_event ce on ce.id = s.controlled_event_id " +
    "and ce.calling_system_id = 402 and ji.controlled_status = 'CONTROLLED' " +
    "and ce.external_id = :externalId", nativeQuery = true)
List<ExperimentDetails> getExperimentDetails(@Param("externalId") String externalId);

或者也可以通过配置Spring Boot的JPA命名策略自动处理下划线转驼峰,无需手动加别名:
在application.properties中添加:

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl

方案二:使用复合主键(若必须保留@Entity)

如果需要将ExperimentDetails作为JPA实体,需定义复合主键来唯一标识每条记录:

  1. 创建复合主键类(实现Serializable接口)
package com.pdb.testdbconn.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExperimentDetailsId implements Serializable {
    private String externalId;
    private String jurisdictionName; // 与externalId组合唯一标识记录
}
  1. 修改实体类:使用@IdClass指定复合主键
package com.pdb.testdbconn.dto;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@IdClass(ExperimentDetailsId.class)
public class ExperimentDetails {
    @Id
    private String externalId;
    @Id
    private String jurisdictionName;
    private String isid;
    private String name;
    private String controlledStatus;
    private String resultComments;
    private String codeName;
    private String corporateId;
}

这样JPA会通过复合主键识别不同实体,不会复用缓存对象。


内容的提问来源于stack exchange,提问作者Altaf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 14:01:30