9
em.getTransaction().begin();

StringData sd = em.find(StringData.class, key);
System.out.println("Old value: " + sd.getData());
sd.setData(newValue);
// em.persist(sd);

em.getTransaction().commit();

As you can see, I'm not calling persist, it's commented out, because I'm dry running this code first. However, as it turns out it's not so very dry. Upon inspecting the database, I see the data is changed (fortunately it's a test database).

Apparently my understanding of Hibernate/JPA is flawed. Isn't calling persist always required to change data? And if not, what are the rules on when something is saved?

Bart van Heukelom
  • 43,244
  • 59
  • 186
  • 301

3 Answers3

11

Yes, when a flush (flush are also done with a commit) is done managed entities are saved if any change is detected on that entity, it's called dirty checking.

Pablo
  • 3,655
  • 2
  • 30
  • 44
  • Good to know. Can that be relied upon, or is a `persist` call still wise? – Bart van Heukelom Feb 08 '12 at 16:25
  • @Bart Only **managed** entities are saved this way, managed means that the entity manager used to load those entities is not closed yet, so be careful. And persist works to create a new entity. If you use it in an already existing entity (like here) it will throw an exception. Take a look at the API: [link](http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html) – Pablo Feb 08 '12 at 16:32
  • But I use `persist` on loaded entities all the time, without exceptions. – Bart van Heukelom Feb 08 '12 at 16:43
  • @Bart Strange, in the API for persist: _"EntityExistsException - if the entity already exists. (If the entity already exists, the EntityExistsException may be thrown when the persist operation is invoked, or the EntityExistsException or another PersistenceException may be thrown at flush or commit time.) "_ – Pablo Feb 08 '12 at 16:47
  • 1
    @Bart OK, it seems that the API is not very accurate, look at the accepted answer: [link](http://stackoverflow.com/questions/4509086/what-is-the-difference-between-persist-and-merge-in-hibernate) – Pablo Feb 08 '12 at 16:53
4
StringData sd = em.find(StringData.class, key);

That line of code retrieves the StringData instance sd from the em session, any changes you make will be saved on flush (when transactions ends) because the object instance is associated with the em session (ie managed).

You could detach it, or return it from the method. Outside of the transaction it is not associated with em session and changes will not be persisted until it is re-attached via merge.

NimChimpsky
  • 46,453
  • 60
  • 198
  • 311
  • The important part is not that the transaction is commited, the important part is that the entity manager is closed. If the transaction is commited but the entity manager is not closed, the entity is still associated with the entity manager. – Pablo Feb 08 '12 at 16:38
  • @Pablo So what happens if the entity is changed outside the transaction, but within the entity manager? – Bart van Heukelom Feb 08 '12 at 17:28
  • @Bart The entity manager will try to save it the next time that a flush() or commit() is called. – Pablo Feb 08 '12 at 17:50
0

The accepted answer is slightly misleading. Managed entities are saved automatically on flush but flush is not issued "if any change is detected". This is misleading as it implies that flush happens on any change instantly.

Instead, with the default AUTO flush mode, a flush is triggered on very specific conditions.

Example 1 - If you interleave a native SQL within your transaction.
Example 2 - If you write a JPQL/HQL query that overlaps with cache.
Example 3 - If you exit the transaction normally.

My point is that it's not an immediate flush but rather triggered only when certain conditions are met. This is subtle but important distinction.

Reference - https://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/flushing/Flushing.html

Dhruv Gairola
  • 9,102
  • 5
  • 39
  • 43
  • I didn't mean to imply in my answer that flushs are triggered when any change is detected. I merely meant that a flush will save the entity when any change to the entity is detected. I'll change the answer a bit to make it clear. – Pablo Jun 21 '21 at 12:15