gpt4 book ai didi

java - 为什么 Hibernate 在现有值为 null 时执行 INSERT 而不是 UPDATE?

转载 作者:行者123 更新时间:2023-11-30 10:27:52 26 4
gpt4 key购买 nike

问题

我在合并我的一个 Hibernate 实体时发现了约束冲突。有两个表 A 和 B,其中一个保存元数据,另一个是字符串值的映射。

在表 B 中有一个组合主键在 (id, key) 上。

现在,当我合并 A 的一个现有实例(它也有多个 B 的条目)时,Hibernate 将为 B 执行 UPDATE 和 INSERT 语句。

UPDATE 语句没有问题,但是INSERT 语句无法执行,因为它会导致违反约束,因为(id, key) 是唯一组合。

我发现只有当 B 中的现有值为 null 时才会出现此问题。

我使用的是 Oracle 11、JPA 2.1 和 EJB 3.2。不过,不完全确定如何确定 Hibernate 版本。

一个例子

让我们假设这些是表 B 的条目:

23, fooKey, foo
23, barKey, bar
23, errorKey, null

现在,当我合并 A (id = 23) 时,将为 fooKeybarKey 执行更新语句。但是,对于 errorKey,Hibernate 将改为发出 INSERT 语句并导致违反约束。

所以我的问题是:

  1. 当现有值为 null 时,为什么 Hibernate 执行 INSERT 语句?
  2. 我该如何解决这个问题?

我的数据库

表A(id, version, lastUpdate )

表B(id,key,value)

我的实体

@Entity
public class A {
@Id
public long id;
public long version = 0;
public Date lastUpdate = new Date();

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "B", joinColumns = @JoinColumn(name = "ID"))
@MapKeyColumn(name = "KEY")
@Column(name = "VALUE", length = 2000)
public Map<String, String> myMapping = new HashMap<String, String>();

// Setters and getters...
}

最佳答案

1 的答案:从 Hibernate 的角度来看,集合中的 NULL 值元素不存在。因此,当您将元素“更新”为非空值时,Hibernate 会执行 INSERT 语句。

对 2 的回答:使用 Hibernate 时应避免在集合中使用空值(或包装它们),使用 Oracle 时应避免使用空格(见下文)。

我用 Oracle 重现了你的问题。首先,我存储一个“”(空字符串)值元素,然后将其更新为任何其他字符串。我使用 log4jdbc 来检查 Hibernate 发出的实际语句。

这是演示(Oracle 失败,H2 有效):

http://peter.risko.hu/java_incubator/jpa_hibernate_collectionBehaviour_null_empty_string_h2_oracle_log4jdbc.zip

最初的坚持:

A a = new A();
a.setId(1);
a.setLastUpdate(new Date());
a.setVersion(1);

Map<String, String> myMap = new HashMap<>();
myMap.put("b", "");
a.setMyMapping(myMap);

em.getTransaction().begin();
em.persist(a);
em.getTransaction().commit();
em.clear();

这是最初坚持期间发生的事情:

insert into A (lastUpdate, version, id) values (to_timestamp('07/13/2017 12:28:37.112', 'mm/dd/yyyy hh24:mi:ss.ff3'), 1, 1)
insert into B (ID, KEY, VALUE) values (1, 'b', '')

Oracle 是如此“聪明”(愚蠢?),它插入 NULL 而不是空字符串。所以在db中B表中有(1, 'b', NULL)记录:

select * from b;
ID KEY VALUE
1 b (null)

现在是查找:

A found = em.find(A.class, 1l);
System.out.println("found no. 1: " + found);

请注意,输出清楚地表明 Hibarnate 尚未选取 NULL 值元素:

found no. 1: id: 1, version: 1, mapping: {}

现在出现了与“更新”值的合并——假设更新后的值是“任何”。请注意,它实际上是一个补充:

found.myMapping.put("b", "anything");
em.getTransaction().begin();
em.merge(found);
em.getTransaction().commit();
em.clear();

因为这是一个添加,这就是 Hibernate 将尝试做的事情:

insert into B (ID, KEY, VALUE) values (1, 'b', 'anything')

插入失败并显示 ORA-00001:违反了唯一约束 (XXX.SYS_C0045198):B 中确实有一条记录具有此主键 (1, 'b')。

关于此的另一篇不错的文章:

http://koenserneels.blogspot.hu/2012/09/hibernates-map-behaviour.html

关于java - 为什么 Hibernate 在现有值为 null 时执行 INSERT 而不是 UPDATE?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45056805/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com