The em.refresh(person)
in the following code does not work. Rather than refreshing the person
with a fresh value from database, it resets (undo or discards) the changes made in the cache. I am not able to understand why?
em.getTransaction().begin();
Person person = em.find(Person.class, 2L); //Person[id=2L, age=23]
person.setAge(24);
System.out.println(person.getAge()); //it prints 24
//Person with id=2 in database gets modified concurrently somehow,
//its age becomes 25 in PERSON table (by an SQL update for example "UPDATE person SET age=25 WHERE id=2")
em.refresh(person); // attempts to load fresh value from database with a SELECT...
System.out.println(person.getAge()); //it prints 23, rather than 25, why?
em.getTransaction().commit();
em.close();
Could someone help me understand this behavior by the refresh()
method of EntityManager
?
CodePudding user response:
If you want to see changes made from other transactions while inside a transaction you need to change the isolation level to READ_COMMITTED
<property name="hibernate.connection.isolation">TRANSACTION_READ_COMMITTED</property>
A few definitions to clarify the discussion:
- Repeatable read: essentially means that within a transaction the database will see the same value, unless the data was modified within that transaction
- Hibernate flush: the modifications made in the session (e.g.
person.setAge(24);
) are not visible by the database until they are flushed. A flush occurs when calling em.flush, committing or, typically, when executing a query such asselect * from Person where name=...
but not when calling refresh() - Hibernate refresh: reading the data from the database and updating the session/1st level cache with that data.
So basically:
- You're modifying the age by calling setAge() but that change is not flushed, hence not visible by the database
- You're updating from another session but that change is not visible either because the transactions are isolated (unless using READ_COMMITTED)
- When refresh is called the database is not aware that setAge() was called and it isolates the update from another transaction, so it shows 23