How to use Bean Managed Transactions with EJB3, JPA and JTA
During a “little” project I am doing in my spare time, I found out that switching to Bean Managed Transactions (BMT) wasn’t as easy as I expected. When you’ve used Container Managed Transactions (CMT) and are switching to BMT with JTA like I was, you need to know the following:
First of all the persistence unit needs to define a <jta-data-source> and not a <non-jta-data-source>
<persistence-unit name=”TopLinkPU”>
<provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
<jta-data-source>jdbc/gpslocationsharing</jta-data-source>
</persistence-unit>
Because you are using JTA you can’t fetch a new EntityTransaction from the entity manager. You’ll have to get a UserTransaction from the EJBContext. To do this, have the EJB container inject the EJBContext using the following code:
@Resource
private EJBContext context;
After the container has injected the EJBContext you can simply start, use and commit a transaction like this:
UserTransaction tx = context.getUserTransaction();
tx.begin();
em.persist(client);
tx.commit();
Knowing the above, using BMT with EJB3, JTA and JPA is really easy! The point is to find the right information. And now you have!
Enjoy!
After following the above steps I am still getting the following exception:
java.lang.IllegalStateException: Container AddStationBean: it is illegal to inject UserTransaction into a CMT bean
16:12:44,382 ERROR [STDERR] at org.jboss.ejb3.BaseSessionContext.getUserTransaction(BaseSessionContext.java:248)
16:12:44,382 ERROR [STDERR] at com.avaya.iptcm.cm.ui.station.AddStationBean.addStationTemplateAssociation(AddStationBean.java:733)
16:12:44,382 ERROR [STDERR] at com.avaya.iptcm.cm.ui.station.AddStationBean.addStation(AddStationBean.java:705)
…
The exception says you’re still using a Container Managed Transaction bean. Switching to a BMT bean is something i didn’t mention in the article, just the problems that occur after that.
You forgot to change the transaction type of the bean to BMT.
Hi Geert,
sorry but I’m starting with EJB3 development, and translations.
Transaction is BMT.
For every Entity (POJO) I have a Dao (Common CRUD operations in an extended abstract class) as stateless SB (transactionmanager set to BMT).
From a client (Eclipse RCP/RAP) I have to manage a transaction, to accomplish this I have a Statefull SB to begin/commit/rollback a transaction (injected usertransaction).
From the client I do:
SFSB.begin();
Entity e = new Entity(param1,param2);
SLDao.save(e); // throws an Exception:
/*
Persisting object: javax.persistence.TransactionRequiredException: EntityManager must be access within a transaction
*/
in the save method I do:
…
em.joinTransaction(); // em is injected EntityManager –> here throws exception!
em.persist(e);
…
Have you any Idea?
Have you any complex client – server transactions example?
Thank you.
Kindly
elvisd79
Hey Elvis,
The fact that the exception is thrown means that your “statefull SB to begin/commit/rollback” didn’t start a transaction. Try testing the DAO with a Unit test in which you manually start a transaction and call the DAO.
Hello Geert,
I apologize I’m a little off topic but this is a problem that’s been bothering me for some time now. If I use JTA transaction how can I handle the exceptions? Especially the ones related to breaking constraints in the database. Small example:
java.lang.RuntimeException: javax.transaction.RollbackException: [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] Can’t commit because the transaction is in aborted state
.. there are some additional Caused by .. to eventually get to the last Caused by:
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
If I try to catch javax.transaction.RollbackException along with a general Exception the error will be caught by the general Exception block and not RollbackException.
Maybe you can give me some hints.
Thanks,
Marius
Clarifying this point (for beginners):
@TransactionManagement:
specifies if CMT or BMT is used for a particular bean, the default is CMT, the options are
•TransactionManagementType.CONTAINER
•TransactionManagementType.BEAN