Reputation: 2339
Could someone explain to me the reason of the following behavior?
EntityA
is being first created and then persisted using em.persist(..)
method. @PrePersist
callback is executed before the transaction ends. It works fine.
In the new transaction EntityA
is obtained using em query. Then, some operations modifying its persistable fields are executed and this transaction ends. But on em.flush()
, the @PreUpdate
method is never called nor is @PrePersist
(the latter I anticipated). Why?
// EDIT
That's the trace just before failure. "Done materializing entity" is the effect of the first operation in the transaction that fails.
DEBUG: org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [com.example.entity#1]
DEBUG: org.hibernate.event.internal.AbstractFlushingEventListener - Processing flush-time cascades
DEBUG: org.hibernate.ejb.AbstractEntityManagerImpl - Mark transaction for rollback
DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Initiating transaction rollback
DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Rolling back JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@341a736]
DEBUG: org.hibernate.engine.transaction.spi.AbstractTransactionImpl - rolling back
DEBUG: org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - rolled JDBC Connection
Thanks!
Upvotes: 4
Views: 17745
Reputation: 6658
In my case @Transactional
& @Modifying
were missing in Service layer update method.
Upvotes: 0
Reputation: 11841
In the new transaction, @PrePersist
would be called if you performed a merge
to update EntityA
's state. Simply modifying EntityA
's persistent fields without a merge will not result in a call to @PrePersist
It is similar for @PreUpdate
, however is not guaranteed that the PreUpdate
callback is invoked when an entity is persisted and then modified in a single transaction (which is not the case in your example).
If you are using a transaction-scoped container-managed entity manager, then when a transaction ends, those entities become detached. This is likely what is happening when your first transaction completes. These detached entities will continue to live outside of the persistence context in which they were persisted, however the state of those entities are no longer guaranteed to be synchronized with the database. To ensure their state is synchronized, you should perform a merge
in your second transaction. This will cause the resulting entity to be managed by the persistence context and thus able to be synchronized with the database.
If you don't like this behavior you can choose to use an extended persistence context.
Upvotes: 5