Dear Hibernate community
I've spent already a lot of time trying to figure out why hibernate triggers SQL statements for elements in a map which have not been touched.
I have the following scenario. I have a one-to-many bidrectional relationship between two objects. The child objects are stored in a map. Hibernate triggers update statements for all elements in a map if a new object has been added to this map.
I don't understand why this is necessary.
hibernate-core version is 5.2.7.Final
My database consists of two tables: person and task. These are the mappings:
Person.hbm.xml:
Code:
<hibernate-mapping>
<class name="persistency.test.Person" table="person" lazy="true">
<id name="dbKey" type="long" access="field" column="dbkey">
<generator class="native" />
</id>
<property name="name" type="java.lang.String" length="20" access="field" />
<map name="tasks" cascade="all-delete-orphan" inverse="true" access="field">
<key column="person_dbkey" />
<map-key type="string" column="name" />
<one-to-many class="persistency.test.Task" />
</map>
</class>
</hibernate-mapping>
Person.java
Code:
public class Person {
private String name;
private long dbKey;
private Map<String, Task> tasks = new HashMap<>();
public void addTask(Task task) {
task.setOwner(this);
this.tasks.put(task.getName(), task);
}
}
Task.hbm.xml:
Code:
<hibernate-mapping>
<class name="persistency.test.Task" table="task" lazy="true">
<id name="dbKey" type="long" access="field" column="dbkey">
<generator class="native" />
</id>
<property name="name" type="java.lang.String" length="20" access="field" />
<property name="description" type="java.lang.String" length="100" access="field" />
<many-to-one name="owner" column="person_dbkey" class="persistency.test.Person" access="field" />
</class>
</hibernate-mapping>
Task.java
Code:
public class Task {
private String name;
private long dbKey;
private Person owner;
private String description;
public Task(String name, String description) {
this.name = name;
this.description = description;
}
public Task() { }
public String getName() {
return name;
}
public void setOwner(Person owner) {
this.owner = owner;
}
}
Code:
session.beginTransaction();
Person person = session.load(Person.class, 139000l);
person.addTask(new Task("Cleaning", "Floor, Roof"));
session.getTransaction().commit();
Triggered SQL statements by hibernate:
Code:
select person0_.dbkey as dbkey1_0_0_, person0_.name as name2_0_0_ from XHM_2.person person0_ where person0_.dbkey=?
select tasks0_.person_dbkey as person_dbkey4_1_0_, tasks0_.dbkey as dbkey1_1_0_, tasks0_.name as name2_0_, tasks0_.dbkey as dbkey1_1_1_, tasks0_.name as name2_1_1_, tasks0_.description as description3_1_1_, tasks0_.person_dbkey as person_dbkey4_1_1_ from XHM_2.task tasks0_ where tasks0_.person_dbkey=?
select XHM_2.hibernate_sequence.nextval from dual
insert into XHM_2.task (name, description, person_dbkey, dbkey) values ('Cleaning', 'Floor, Roof', '139000', '224000')
update XHM_2.task set name='Eating' where dbkey='221000'
update XHM_2.task set name='Cooking' where dbkey='218000'
update XHM_2.task set name='Reading' where dbkey='225000'
update XHM_2.task set name='Cleaning' where dbkey='224000'
Person table
Code:
DBKEY | NAME
139000 | John
Task table after insert
Code:
DBKEY | NAME | PERSON_DBKEY | DESCRIPTION
224000 | Cleaning | 139000 | Floor, Roof
221000 | Eating | 139000 | Food
218000 | Cooking | 139000 | Food
225000 | Reading | 139000 | Food
I don't understand why hibernate triggers the last four update statements. They update the names of the task elements to the same names they had before. There are four update statements because the tasks table currently contains four elements. The task name is used as key in person.tasks map.
We have this problem in production with a large map and it causes a performance issue if hibernate triggers thousands of update statements if only one element has been added to a map.
Any help is very much appreciated