Spring Boot Repository返回重复值问题排查求助
看起来你遇到的问题核心在于JPA实体映射的主键配置错误,导致JPA将数据库中不同的账户记录识别为同一个实体实例,最终返回重复的DTO数据。
为什么会出现重复记录?
JPA依靠实体的主键来区分不同的对象实例。如果你的AccountView实体把customer_number(客户编号)标记成了主键@Id,那所有属于同一个客户的账户都会被JPA判定为同一个实体——哪怕它们的账户编号(account_number)完全不同。这种情况下,JPA在查询时会把后续加载的同客户账户都替换成第一个加载的实例,最终返回的列表里全是重复的对象。
你可以先看一下控制台打印的account列表,如果打印出来的AccountView对象已经是重复的,那百分百是实体主键的问题。
解决方案
1. 修正AccountView的主键配置
每个账户应该有自己的唯一标识,也就是account_number,把它设置为主键才是正确的:
@Entity @Table(name = "你的账户视图表名") public class AccountView { @Id @Column(name = "account_number") private String accountNumber; // 账户编号作为唯一主键 private String customerNumber; // 客户编号作为普通字段 // 其他字段的映射... // Getter和Setter方法 }
2. 如果是复合主键的场景(比如视图没有单一唯一键)
如果你的AccountView是数据库视图,没有单一的唯一字段,可以用复合主键来标记,比如结合customer_number和account_number:
首先定义复合主键类:
@Embeddable public class AccountViewPK implements Serializable { @Column(name = "customer_number") private String customerNumber; @Column(name = "account_number") private String accountNumber; // 必须实现无参构造、equals和hashCode方法 public AccountViewPK() {} public AccountViewPK(String customerNumber, String accountNumber) { this.customerNumber = customerNumber; this.accountNumber = accountNumber; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AccountViewPK that = (AccountViewPK) o; return Objects.equals(customerNumber, that.customerNumber) && Objects.equals(accountNumber, that.accountNumber); } @Override public int hashCode() { return Objects.hash(customerNumber, accountNumber); } }
然后在AccountView中使用复合主键:
@Entity @Table(name = "你的账户视图表名") public class AccountView { @EmbeddedId private AccountViewPK id; // 其他字段的映射... // Getter和Setter方法 }
同时更新Repository的泛型:
@Repository public interface AccountRepository extends JpaRepository<AccountView, AccountViewPK> { List<AccountView> getByCustomerNumber(String cif); List<AccountView> getByCustomerNumberIn(List<String> cifList); }
3. 验证Mapper转换逻辑(可选)
如果控制台打印的AccountView列表是正确的不同对象,但DTO重复,再检查AccountMapper的toAccountDto方法——不过从你贴的代码看,Mapper都是从account对象取字段值,没有硬编码或错误赋值的问题,所以这个概率很低。
按照上面的步骤修正后,JPA就能正确识别每个不同的账户记录,返回的DTO列表自然就会和数据库中的数据一致了。
内容的提问来源于stack exchange,提问作者user14528173

