我有一个简单的实体Code,我需要将其保存到MySQL数据库。
public class Code implements Serializable {
@Id
private String key;
private String description;
...getters and setters...
}
用户提供一个文件,其中包含我读取的密钥,描述对,转换为Code对象,然后使用em.merge(代码)插入单个事务中。该文件通常会有重复的条目,我在处理它时首先将它们添加到键字区域上的地图上。
虽然按键仅因情况而异(例如:XYZ和XyZ),但会出现问题。当然,我的地图将包含两个条目,但在合并过程中,MySQL将两个键视为相同,并且对merge的调用失败,并且MySQLIntegrityConstraintViolationException。
我可以通过在读取密钥时对键进行大写来轻松解决这个问题,但我想知道究竟出了什么问题。我得出的结论是,JPA认为XYZ和XyZ是不同的密钥,但MySQL认为它们是相同的。因此,当JPA检查其已知密钥列表(或执行任何操作以确定是否需要执行插入或更新)时,它无法找到先前的插入并发出另一个然后失败的插入。这是正确的吗?除了更好地过滤客户数据之外,还有其他方法吗?
我没有在Code类上定义.equals或.hashCode,所以这可能是问题所在。
答案 0 :(得分:2)
我没有在Code类上定义.equals或.hashCode,所以这可能是问题所在。
嗯,你真的应该,你不想继承Object
对于实体的行为。您是否要使用主键,进行区分大小写的比较或使用业务标识是另一个故事,但您当然不希望使用引用相等。您不需要以下实体:
Code code1 = new Code();
code1.setKey("abc");
Code code2 = new Code();
code2.setKey("abc");
被JPA视为不同。
其次,如果您希望能够插入一个以XYZ
为键,另一个为XyZ
的实体,那么您应该使用区分大小写的列类型(您可以使{{1通过使用varchar
属性对列区分大小写)或者您将获得主键约束违规。
所以,总结一下:
binary
(和equals
),决定是否需要对hashCode
进行区分大小写的比较。答案 1 :(得分:1)
这取决于您的列在mySQL中的定义方式。 mySQL是奇怪的数据库,因为VARCHAR和类似的列默认为不区分大小写的匹配。如果您希望XYZ和XyZ成为不同的合法选项,则需要更改CREATE TABLE语句以创建区分大小写的列(请参阅您的mySQL版本的文档。)
可能是这样的:
CREATE TABLE code (
key VARCHAR(32) BINARY,
value VARCHAR(32) BINARY
)