Java 由于密钥重复,JPA合并失败

Java 由于密钥重复,JPA合并失败,java,orm,jpa,merge,persistence,Java,Orm,Jpa,Merge,Persistence,我有一个简单的实体,代码,我需要将它持久化到MySQL数据库 public class Code implements Serializable { @Id private String key; private String description; ...getters and setters... } 用户提供了一个完整的文件,其中包含我读取的密钥、描述对,将其转换为代码对象,然后使用em.merge(Code)插入到单个事务中。该文件通常会有重复的条

我有一个简单的实体,代码,我需要将它持久化到MySQL数据库

public class Code implements Serializable {

    @Id
    private String key;
    private String description;

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

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

我可以很容易地解决这个问题,通过大写键,因为我读他们,但我想确切地了解到底是什么出了问题。我得出的结论是,JPA认为XYZ和XYZ是不同的键,而MySQL认为它们是相同的。同样,当JPA检查其已知密钥列表时(或者做任何事情来确定是否需要执行插入或更新),它无法找到上一个插入并发出另一个插入,然后失败。这是科伦特吗?除了更好地过滤客户机数据之外,还有其他办法吗


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

这取决于您的列在mySQL中的定义方式。mySQL是数据库中的奇人,因为VARCHAR和类似的列默认为不区分大小写的匹配。如果希望XYZ和XYZ是不同的法律选项,则需要更改CREATETABLE语句以创建区分大小写的列(有关mySQL版本的信息,请参阅文档)

可能是这样的:

CREATE TABLE code (
  key VARCHAR(32) BINARY,
  value VARCHAR(32) BINARY
)
我还没有在Code类上定义.equals或.hashCode,所以这可能就是问题所在

嗯,您确实应该这样做,您不希望继承实体的
对象的行为。您是想使用主键,进行区分大小写的比较,还是使用业务标识是另一回事,但您肯定不想使用引用相等。您不需要以下实体:

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

Code code2 = new Code();
code2.setKey("abc");
被JPA视为不同

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

因此,总结一下:

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

或者,根据您的JPA提供商是谁,您可以设置mySQL方言,以便它在查询本身上指定区分大小写。