The following code is from JPA
specs. I could not understand why em.joinTransaction()
is required in createLineItem(int quantity)
.
Can anyone provide an apt explanation?
@Stateful
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
private Order order;
private Product product;
@PostConstruct
public void init() {
em = emf.createEntityManager();
}
public void initOrder(Long id) {
order = em.find(Order.class, id);
}
public void initProduct(String name) {
product = (Product) em
.createQuery("select p from Product p where p.name = :name")
.setParameter("name", name).getSingleResult();
}
public LineItem createLineItem(int quantity) {
em.joinTransaction();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
return li;
}
@Remove
public void destroy() {
em.close();
}
}
entityManager.joinTransaction() is called when a JTA transaction is active for a JTA entity manager. entityManager.getTransaction().begin() is called for a RESOURCE_LOCAL entity manager.
In JPA, the EntityManager interface is used to allow applications to manage and search for entities in the relational database. The EntityManager is an API that manages the lifecycle of entity instances. An EntityManager object manages a set of entities that are defined by a persistence unit.
The EntityManager. refresh() operation is used to refresh an object's state from the database. This will revert any non-flushed changes made in the current transaction to the object, and refresh its state to what is currently defined on the database.
First, a few words of theory...
An application-managed entity manager participates in a JTA transaction in one of two ways.
joinTransaction()
on the EntityManager
interface. Once synchronized, the persistence context will automatically be flushed when the transaction commits.After reading the above definition a few questions may arise:
how do we know that ShoppingCartImpl
participates in JTA transaction ?
Because the class has been annotated with @Stateful
(or @Stateless
) annotation so the intention is to execute the class within Java EE environment which by default uses JTA transactions. A class doesn't need such annotation, if it will be executed in Java SE environment.
how do we know application-managed entity manager is used in this particular case?
Because we are using @PersistenceUnit
annotation to inject EntityManagerFactory
and then manually creating and destroying EntityManager
. By doing this we are telling Java EE container that we don't want our transaction to be automatically managed (like in case of transaction-scoped entity manager or extended entity manager types).
why em.joinTransaction()
is required in createLineItem
method?
By calling em.joinTransaction()
we notify the application-managed persistence context that it should synchronize itself with the current JTA transaction. Without such call the changes to Order
would not be flushed to the underlying database when the transaction commits (at the end of createLineItem
method).
NOTE: since EntityManagerFactory
instances are thread-safe and EntityManager
instances are not, an application must not call em.joinTransaction()
on the same entity manager in multiple concurrent transactions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With