Spring Data JPA save() 方法不遵循 hashcode/equals 合约

Posted

技术标签:

【中文标题】Spring Data JPA save() 方法不遵循 hashcode/equals 合约【英文标题】:Spring Data JPA save() method not following the hashcode/equals contract 【发布时间】:2018-07-15 02:11:51 【问题描述】:

我在下面的简单员工实体中实现哈希码/等于时遇到问题。我想要实现相等的自定义字段是“_id”字段。

当我保存两个具有相同值的员工对象时,即“111”,我希望在数据库中只保存一个值。但是,我最终保存了 2 条员工记录。

实体代码如下

    @Entity
    @Table(name = "employee")
    public class Employee 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "employee_id")
    private Long employeeId;

    @Column(name = "employeehexa_id") 
    private String _id;

    @Override
    public int hashCode() 
        HashCodeBuilder hcb = new HashCodeBuilder();
        hcb.append(_id);
        return hcb.toHashCode();
       


    @Override
    public boolean equals(Object obj) 
        if (this == obj) 
            return true;
        
        if (!(obj instanceof Employee)) 
            return false;
        
        Employee that = (Employee) obj;
        EqualsBuilder eb = new EqualsBuilder();
        eb.append(_id, that._id);
        return eb.isEquals();
    

    // Required Constructors, getters, setters not shown for brevity
   

下面是我用相同的_id保存两个对象的调用

@Autowired
private EmployeeRepo employeeRepo;

@RequestMapping("/test")
String Test() throws Exception 

    Employee e1 = new Employee("111");
    Employee e2 = new Employee("111");
     System.out.println(e1.equals(e2)); // prints true, implying hashcode and equals working fine
    employeeRepo.save(e1);
    employeeRepo.save(e2);//Both e1 and e2 are saved inspite of being equal

    return "Completed !";

平等检查似乎工作正常。 spring JpaRepository 的 save() 是否有导致此问题的原因,或者我对如何执行相等/哈希码合同的理解不正确?

我以为我理解相等/哈希码,但看起来并非如此。任何帮助表示赞赏。谢谢。

【问题讨论】:

这与 Spring Data JPA 无关,而仅与 JPA 的工作方式有关。如果您不想保存它,请在数据库级别创建唯一约束。 【参考方案1】:

根据这个答案https://***.com/a/11881628/5695673,您可能有 2 条记录,因为您的字段 employeeId 对于您的实体来说是不同的,因此对于 spring-data,这两个实体是不同的。 要测试您的 equals()/hashCode() 是否按预期工作,您可以尝试将您的实体放入一个检查对象相等性的集合中(即 Set)并尝试一次性保存所有集合。

例子:

Set<Employee> employees = new HashSet<Employee>();
employees.add( new Employee("111"));
employees.add( new Employee("111"));

System.out.println(employees.size()); //1
employeeRepo.save(employees); // 1 record

更多信息在这里:https://developer.jboss.org/wiki/EqualsandHashCode?_sscc=t

【讨论】:

谢谢。是的,我知道收集方法。但有兴趣单独保存。确保 spring data save() 强制执行 hashcode/equals 的唯一方法是将对象放入集合中并保存它们吗? IMO 是的,但这不是 spring-data 问题,这更像是 JPA 相关主题。

以上是关于Spring Data JPA save() 方法不遵循 hashcode/equals 合约的主要内容,如果未能解决你的问题,请参考以下文章

Spring Batch/Data JPA 应用程序在调用 JPA 存储库(save、saveAll)方法时不会将数据持久化/保存到 Postgres 数据库

spring-data-jpa

Spring data JPA - CrudRepository save() 上的 ConstraintViolationException

为啥在 Spring Data JPA Repository 上的 save() 之后使用返回的实例?

spring-data-jpa 使用 @Query 和 @Modifying 插入而不使用 nativeQuery 或 save() 或 saveAndFlush()

Spring Data Jpa:保存方法仅返回选择,但不执行插入