NamedNativeQuery查询返回结果与数据库实际数据不一致如何解决
问题原因及解决方案
核心问题原因
- SQL语法与逻辑错误
- 聚合函数
SUM未搭配GROUP BY子句:使用聚合函数但没有对非聚合字段分组时,SQL会将所有行聚合为单行汇总结果,返回的所有行的SUM值都是全表汇总结果,自然和单条存储数据不符 - SELECT字段冗余:你查询了
op.ex字段,但OperorEntity实体类中没有对应映射字段,会导致结果列和实体字段映射错位 - 语法错误:SELECT子句最后一个字段
SUM (b.bri) BRI后多了多余的逗号,会直接导致SQL执行报错
- 聚合函数
- 字段映射不匹配
SQL中SUM (b.vx) VX的别名是VX,但实体类中对应字段的注解是@Column(name = "vn"),别名和列名不匹配,会导致字段无法正确映射赋值 - 主键重复导致缓存复用
你的实体类主键@Id标注的是cod字段,你返回的4行数据cod值都相同,JPA默认会把相同主键的实体视为同一对象,优先复用持久化上下文或二级缓存中已存在的实体实例,所以后面3行查询到的结果都会被替换成第一行的缓存值,你还开启了只读二级缓存,进一步加剧了这个问题。
解决方案
第一步:修正SQL语句
@NamedNativeQuery( name = "a.findOperor", resultClass = OperorEntity.class, query = " select\n" + " b.cod, " + " b.c id, \n" + // 别名改为vn和实体列名对应 " SUM (b.vx) vn,\n" + " SUM (b.vi) VI,\n" + " SUM (b.an) AN,\n" + " SUM (b.ai) AI,\n" + " SUM (b.pn) PN,\n" + " SUM (b.pi) PI,\n" + " SUM (b.rn) RN,\n" + " SUM (b.ri) RI,\n" + " SUM (b.prn) PRN,\n" + " SUM (b.pri) PRI,\n" + " SUM (b.bn) BN,\n" + " SUM (b.bpg) BPG,\n" + // 删掉末尾多余的逗号 " SUM (b.bri) BRI\n" + " FROM X b \n" + // 新增GROUP BY,所有非聚合字段都要加入分组 " GROUP BY b.cod, b.c" )
第二步:解决主键重复问题
你当前的查询是聚合结果,不属于原始的单条Operor实体记录,更推荐你使用专门的DTO类接收查询结果,而非复用实体类:
- 定义普通POJO类,包含所有查询返回字段,不需要加
@Entity、@Id等实体注解 - 将
@NamedNativeQuery的resultClass替换为你新建的DTO类,搭配@SqlResultSetMapping完成映射即可
如果你一定要继续使用OperorEntity,可以将主键改为复合主键,用cod和id两个字段共同作为主键,保证每行返回结果的主键唯一,就不会出现缓存复用的问题。
第三步:缓存调整(可选)
如果只是临时测试验证结果,可以在查询时添加提示禁用缓存:
Query query = entityManager.createNamedQuery("a.findOperor"); query.setHint("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
内容的提问来源于stack exchange,提问作者Marco Sciuto
相关产品推荐
相关产品推荐

