java - 由于重复键,JPA 合并失败

标签 java orm jpa merge persistence

我有一个简单的实体代码,我需要将其保存到 MySQL 数据库中。

public class Code implements Serializable {

    @Id
    private String key;
    private String description;

    ...getters and setters...
}

用户提供了一个包含 key 和描述对的文件,我读取这些文件,将其转换为代码对象,然后使用 em.merge(code) 将其插入到单个事务中。该文件通常会有重复的条目,我通过首先将它们添加到在我读入它们时在关键字段上键入的映射来处理这些条目。

当键仅因大小写不同(例如:XYZ 和 XyZ)时,就会出现问题。当然,我的映射将包含两个条目,但在合并过程中,MySQL 认为这两个键相同,因此合并调用失败并出现 MySQLIntegrityConstraintViolationException。

我可以通过在读入时将键大写来轻松解决此问题,但我想确切地了解出了什么问题。我得出的结论是 JPA 认为 XYZ 和 XyZ 是不同的键,但 MySQL 认为它们是相同的。因此,当 JPA 检查其已知键列表(或执行任何操作以确定是否需要执行插入或更新)时,它无法找到先前的插入并发出另一个插入失败。这是正确的吗?除了更好地过滤客户端数据之外,还有什么解决办法吗?

我没有在 Code 类上定义 .equals 或 .hashCode,所以这可能是问题所在。

最佳答案

I haven't defined .equals or .hashCode on the Code class so perhaps this is the problem.

嗯,你真的应该,你不想继承 Object 实体的行为。无论您是想使用主键、进行区分大小写的比较还是使用业务身份都是另一回事,但您肯定不想使用引用相等性。您不需要以下实体:

Code code1 = new Code();
code1.setKey("abc");

Code code2 = new Code();
code2.setKey("abc");

被 JPA 认为是不同的。

其次,如果您希望能够插入一个以 XYZ 为键的实体和另一个以 XyZ 为键的实体,那么您应该使用区分大小写的列类型(您可以使用 binary 属性使 varchar 列区分大小写),否则您将违反主键约束。

总结一下:

  • 实现 equals(和 hashCode),决定是否需要对 key 进行区分大小写的比较。
  • 在数据库级别使用适当的列类型。

关于java - 由于重复键,JPA 合并失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2776942/

相关文章:

java - 将 Java SE 升级到 Java EE 以及 Eclipse

java - JAXB 忽略 package-info.java 中的 @XmlAccessorFactory

java - 如何将 launch4j 与 Java 自定义运行时镜像一起使用?

laravel - 如何在 Laravel Eloquent 中指定我的列不能为空?

hibernate - 什么时候适合使用双向关联,什么时候不适合?

java - JPA Criteria builder 如何对逻辑 AND 条件进行分组

java - Java 中的 ROT-N(或 ROT-X)函数

python - Django:检查 values_list 中的值是否有和没有 prefetch_related/select_related

java - 从 JPA 中的对象中选择列表

java - 枚举 Java 未保存为带有枚举注释的字符串