Let's say I have a stateless session bean, Foo. I have injected an EntityManager into Foo using CDI.
I've read that by default, the EntityManager will be transaction-scoped and that therefore any entities that are in the EntityManager's persistence context will be managed by the EntityManager until the end of the transaction.
But what if the transaction starts outside of Foo, in class Bar? So Foo has been injected into Bar, the transaction starts in Bar and then Foo is called within that transaction. Of course, the EntityManager can't manage objects before Foo is created, but what about after the method in Foo returns?
After Foo returns, is the EntityManager somehow still managing the entities it was managing in Foo or have they been detached at that point even though the transaction is still continuing? If I change a value on an entity in Bar after the method in Foo returned, should that change get propagated to the database?
Many thanks!
Edit: Some code to make it clearer
class Bar {
#Inject
Foo foo;
// Transaction starts here
public void doSomething(){
foo.doSomethingElse();
// Transaction is still uncommitted here
// Make a change to an entity here that was in foo's
// entityManager's persistence context
// Does it get picked up and propagated to the db?
// Or is the entityManager gone by this point?
}
// Transaction commits after return of this method
}
#Stateless
class Foo {
#PersistenceContext
EntityManager em;
// This method by default joins the transaction that was already started in Bar
public void doSomethingElse(){
// Do something with entities
}
}
depends on how your transaction boundaries are managed. are you using bean managed transactions? container managed with REQUIRES_NEW? container managed with default boundaries?
i recommend:
https://docs.oracle.com/javaee/5/tutorial/doc/bncij.html
Related
I'm learning about how to create REST API with JPA and Hibernate and a MySQL database and I see this #Transactional annotation. Can someone explain what is the use of this annotation?
For example I have this simple DAO class:
#Repository
public class EmployeeDAOHibernateImpl implements EmployeeDAO {
// define field for entitymanager
private EntityManager entityManager;
// set up constructor injection
#Autowired
public EmployeeDAOHibernateImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
#Transactional
public List<Employee> findAll() {
// get the current hibernate session
Session currentSession = entityManager.unwrap(Session.class);
// create a query
Query<Employee> theQuery =
currentSession.createQuery("from Employee", Employee.class);
// execute query and get result list
List<Employee> employees = theQuery.getResultList();
// return the results
return employees;
}
}
You can see the #Transactional used for findAll() method, but if I delete this #Transactional I get the same output... then what is the use of this #Transactional?
#Transactional annotation is used when you want the certain method/class(=all methods inside) to be executed in a transaction.
Let's assume user A wants to transfer 100$ to user B. What happens is:
We decrease A's account by 100$
We add 100$ to B's account
Let's assume the exception is thrown after succeeding 1) and before executing 2). Now we would have some kind of inconsistency because A lost 100$ while B got nothing.
Transactions means all or nothing. If there is an exception thrown somewhere in the method, changes are not persisted in the database. Something called rollback happens.
If you don't specify #Transactional, each DB call will be in a different transaction.
Generally the #Transactional annotation is written at the service level.
It is used to combine more than one writes on a database as a single atomic operation.
When somebody call the method annotated with #Transactional all or none of the writes on the database is executed.
In the case of read operations it is not useful and so it is in case of a single atomic write. You are using it in a single read (select) so adding or removing the #Transactional annotation has no impact.
The class declares #Transactional on itself or its members, Spring creates a proxy that implements the same interface(s) as the class you’re annotating. In other words, Spring wraps the bean in the proxy and the bean itself has no knowledge of it.
A proxy provides a way for Spring to inject behaviors before, after, or around method calls into the object being proxied.
Internally, its the same as using a transaction advice (using AOP), where a proxy is created first and is invoked before/after the target bean’s method.
The generated proxy object is supplied with a TransactionInterceptor, which is created by Spring. So when the #Transactional method is called from client code, the TransactionInterceptor gets invoked first from the proxy object, which begins the transaction and eventually invokes the method on the target bean. When the invocation finishes, the TransactionInterceptor commits/rolls back the transaction accordingly
Suppose I have a Singleton bean with an EntityManager in it. The singleton also specifies (on method or class level) a transaction attribute REQUIRED. The entity manager is obtained via an #PersistenceContext injection which specifies persistence context type TRANSACTION. For all intents and purposes, if a method on this singleton is invoked with an existing transaction, the entity manager should join the transaction or possibly provide an already existing one linked to that transaction via proxy. If such a method is invoked outside of a transaction a new transaction will be started for the duration of the method invocation.
Now suppose we have a second bean which uses bean-managed transactions and injects the singleton. If it explicitly starts a user transaction and then invokes a method on the singleton, will the entity manager in that method join that user transaction? Will the jump from bean-managed to container-managed transaction context even work? I know the other way around doesn't and forms a barrier.
The singleton class:
#Singleton
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class PersistenceSingleton {
#PersistenceContext(unitName = "test", type = PersistenceContextType.TRANSACTION)
private EntityManager em;
public void doStuff() {
// perform actions with the entity manager that imply changes in the database
}
}
The bean with user transactions (might as well be stateless or stateful):
#Singleton
#TransactionManagement(TransactionManagementType.BEAN)
public class PersistenceFacade {
#EJB
private PeristenceSingleton ps;
#Resource
private UserTransaction userTx;
public void doStuff() {
userTx.begin();
ps.doStuff();
userTx.commit();
}
}
Does the transaction started in method doStuff() of the PersistenceFacade get taken into account when invoking doStuff() on the PersistenceSingleton? Does the entity manager automatically join the transaction and behave as expected from transaction isolation during concurrent access?
UserTransaction is used for changing the default transaction demarcation but we still control the JTA transactions.
https://www.javacodegeeks.com/2013/03/types-of-entity-managers-application-managed-entitymanager.html says:
If you have UserTransaction you can start demarcating what is to be executed within the transaction. Notice that you’re still controlling
the JTA transactions
so The persistence context propagation rule will be applied for UserTransaction demarcation.
pro JPA book says:
When a method is invoked on the transaction-scoped entity manager, it
must first see whether there is a propagated persistence context. If
one exists, the entity manager uses this persistence context to carry
out the operation. All subsequent transaction-scoped entity manager
operations, in this component or any other, will thereafter use this
newly created persistence context. This behavior works independently
of whether container-managed or bean-managed transaction demarcation
has been used.
the answer to your questions is yes(first question)
Does the entity manager automatically join the transaction and behave
as expected from transaction isolation during concurrent access?
entity manager checks the existence of a propagated persistence context and uses it.
So I had been working with Hibernate SessionFactory and its getCurrentSession method for inside a transaction for a while now.
Session session = sessionFactory.getCurrentSession();
and having it interact with other DAO classes within the same test. Switching to JPA though, can I inject a container managed EntityManagerFactory and then replacing the above with
EntityManager entityManager = myFactory.createEntityManager();
and then continue as session interface equivalents in EntityManager in current tests? Performing entityManager.flush() causes
javax.persistence.TransactionRequiredException: no transaction is in progress
.flush() call must be part of a transaction. Either you create one or propagate from calling class using #Transactional annotation.
To create:
entityManager.getTransaction().begin();
// Some DB operations
entityManager.flush();
entityManager.getTransaction().commit(); //commit() will do the flush anyway
If you want to to be part of calling class transaction, then include #Transactional annotation either at method or class level depending on design.
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();
}
}
First, a few words of theory...
An application-managed entity manager participates in a JTA transaction in one of two ways.
If the persistence context is created inside the transaction, the persistence provider will automatically synchronize the persistence context with the transaction.
If the persistence context was created earlier (outside of a transaction or in a transaction that has since ended), the persistence context can be manually synchronized with the transaction by calling 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.
With container-managed JPA persistence, container-managed JTA transactions, and an entity manager injected into stateless local session beans, what does invoking a transaction-not-supported method do to the managed state of an entity? I have read this: https://community.jboss.org/thread/183007 and similar threads, but there seems to be some ambiguity around whether a PC gets propagated to a NOT_SUPPORTED method if they both use injected EMs from the same factory?
Consider this snippet from a a bean that is going to retrieve an item and then invoke a method from another bean:
#PersistenceContext
private EntityManager em;
#Inject
private LeanBean leanBean;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void startHere() {
MyItem item = em.find(MyItem.class, key);
leanBean.txMethod(item);
leanBean.nonTxMethod(item);
}
Now here is LeanBean.java. Note that its two methods have different transaction propagation
#Stateless
#LocalBean
public Class LeanBean {
#PersistenceContext
private EntityManager em;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void txMethod(MyItem item) {
doSomething(item); // item is managed; persistence context propagated with
} // transaction context; em is the same as my caller's em
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void nonTxMethod(MyItem item) {
doSomething(item); // caller's transaction context has been suspsended.
} // did em propagate? is item managed?
}
What I can't figure out from the spec(s):
Inside nonTxMethod, is item in a detached state? What is supposed to happen if I reference em?
What if the method in the calling snippet had been annotated TransactionAttributeType.NOT_SUPPORTED? would would be the state of item in either of the methods inside LeanBean?
What I'm trying to accomplish here is to keep an entity attached inside a method that I do not want to have as part of a transaction.
Inside nonTxMethod, is item in a detached state? What is supposed to
happen if I reference em?
TransactionAttributeType.NOT_SUPPORTED is just a way to tell that your method does not need transaction and you will not be able call persist, merge or remove in EntityManager. But you can still call other methods like em.find(Someclass.class,objectId) . So i think the entity is not in a detached state .
What if the method in the calling snippet had been annotated
TransactionAttributeType.NOT_SUPPORTED? would would be the state of
item in either of the methods inside LeanBean?
This will work exactly the same as previous. Just make sure that , whenever you will put TransactionAttributeType.NOT_SUPPORTED in your calling method eg startHere(), all the subsequent method calls transaction state would be suspended , and if you need trasaction in any of the subsequent calls you have to explicitely specify TransactionAttributeType.REQUIRED above that method .
And by default when you call any session bean's method from outside of the EJB , let from the JSP , the trasaction will automatically started unless you specify explicitly that you don't need transaction.