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

Spring Boot JPA不同查询返回相同实体对象问题排查咨询

问题根本原因

该问题是JPA默认的**一级缓存(持久化上下文缓存)**导致的:

  • 你定义的TotalEntity实体类把data(日期字段)作为唯一主键@Id
  • 当第一个查询返回某个日期的TotalEntity后,该实体会被缓存到当前Session的持久化上下文中
  • 后续查询只要返回相同data值的记录,JPA不会重新做字段映射,直接复用缓存中已有的同主键实体,因此出现先执行的查询结果覆盖后续结果的问题

可行解决方案

可根据业务场景选择以下任意一种方案:

方案1:关闭当前查询的缓存复用(最快捷)

在每个Repository的查询方法上加上@Cacheable(false)注解,强制Hibernate每次查询都重新映射实体,不走持久化上下文缓存:

@Query(/* 原有查询注解内容保持不变 */)
@Cacheable(false) // 新增该行注解
List<TotalEntity> findSpeseTotalsContanti(@Param("mese") Integer mese, @Param("anno") Integer anno);

三个查询方法全部加上该注解即可解决问题。

方案2:修改实体主键定义(从根源解决)

当前实体本质是统计视图,没有唯一的业务主键,可给实体加一个自增伪主键,避免相同日期的记录被判定为同一实体:

@Entity
public class TotalEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id; // 新增伪主键字段
    private Date data;
    private Double totaleBanca; 
    private Double totaleContanti; 
    // 原有getter、setter逻辑保持不变
}

方案3:使用DTO而非实体类接收查询结果(更规范)

因为你的查询是统计聚合结果,不属于实际的数据库表实体,用DTO(普通Java对象)接收查询结果更符合JPA的设计规范,也不会触发实体缓存逻辑:

  1. 先定义DTO类:
public class TotalStatDTO {
    private Date data;
    private Double totaleBanca; 
    private Double totaleContanti;
    // 自行补充全参构造方法、getter、setter
}
  1. 将Repository查询方法的返回类型改为List<TotalStatDTO>即可。

方案4:在查询间隙清空持久化上下文

如果不想改动Repository和实体结构,可以在业务代码中注入EntityManager,在两次查询之间调用clear()方法清空缓存:

@Autowired
private EntityManager entityManager;

// 调用第一个查询后执行
entityManager.clear();
// 再调用后续查询

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 07:45:04