Reputation: 870
I have 2 methods that exhibit a different behavior in regard to flushing in Hibernate.
The first one is:
@Transactional
public void firstMthod(int id, int status) {
Person entity = session.get(Person.class, id);
entity .setStatus(personStatus.registered);
session.merge(entity);
updatePersonAge(id,18);
}
The updatePersonAge
method is located in another class, and the SQL output of this method looks like this:
select personel0_.ID as ID1_119_0_,
personel0_.status as status2_119_0_,
personel0_.age as age3_119_0_,
personel0_.CreatedBy as CreatedBy4_119_0_,
personel0_.UpdatedBy as UpdatedBy5_119_0_,
personel0_.CreatedDate as CreatedDate6_119_0_,
personel0_.UpdatedDate as UpdatedDate7_119_0_,
personel0_.Ip as Ip8_119_0_
from tbl_personel personel0_
where personel0_.ID = ?
update tbl_person set status = ? where ID = ?
update tbl_person set age = ? where ID = ?
and for the second use case, we have the following method:
@Override
@Transactional
public void secondMethod(int id,int courseId, int status) {
Course courseEntity=session.get(Course .class, courseId);
courseEntity.setCreatedDate(new Date());
session.merge(courseEntity);
updatePersonAge(id,18);
}
For which the updatePersonAge
method generates the following SQL output:
select course0_.ID as ID1_120_0_,
course0_.CreatedBy as CreatedBy7_120_0_,
course0_.UpdatedBy as UpdatedBy8_120_0_,
course0_.CreatedDate as CreatedDate9_120_0_,
course0_.UpdatedDate as UpdatedDate10_120_0_,
course0_.Ip as Ip11_120_0_
from tbl_course course0_
where course0_.ID = ?
update tbl_course set created_date = ? where ID = ?
update tbl_person set age = ? where ID = ?
The updatePersoneAge
method is :
public int updatePersonAge(int id,int age){
Query query = session.createQuery("update " + domainClass.getName() + " e set e.age= :age ");
query.setParameter("age ", age);
return query.executeUpdate();
}
According to my expectations, the output of the second method should be the same with the output of the first method. So why the difference? It is really confusing.
Upvotes: 3
Views: 543
Reputation: 153780
First of all, it makes no sense to call merge
on an entity that is already attached to the currently running Session
. Merge
is meant to be used when you want to attach a detached entity.
Second, Hibernate FetchMode.AUTO
flush only triggers the flush if the query about to be run overlaps with entities in the ActionQueue
.
In the first example, because you modified the Person
, and the query is run against a Person
, it makes sense to trigger a flush as otherwise, the SQL query might return stale results.
In the second case, you modify a Course
entity, yet you want to select from Person
. So, there is no need to trigger the flush.
You can control this behavior using Query.addSyncronizedEntityName
.
Upvotes: 2
Reputation: 26522
Apart from updating the age explicitly, inside the updatePersonAge
method, in each of those transactions you are also updating implicitly (by getting an entity and changing one of the fields) other field of a managed entity.
As you are merging those changes, the PErsistence Provider has the obligation to flush those changes at the end of the transaction.
Thats why when you change the status:
Person entity = session.get(Person.class, id);
entity .setStatus(personStatus.registered);
session.merge(entity);
Hibernate persists that change along with the explicit age upate:
update tbl_person set status = ? where ID = ?
update tbl_person set age = ? where ID = ?
In the second method when you change a field of the Course entity:
Course courseEntity=session.get(Course .class, courseId);
courseEntity.setCreatedDate(new Date());
session.merge(courseEntity);
That change is persisted along with the explicit age update:
update tbl_course set created_date = ? where ID = ?
update tbl_person set age = ? where ID = ?
Upvotes: 0