What is best practice for using Database Transactions with Seam when not using EJBs - ie. when deploying Seam as a WAR?
By default Seam JavaBeans support Transactions. I can annotate a method with @Transactional and that will ensure that a transaction is required. Or I can use @Transactional(NEVER) or @Transactional(MANDATORY). What I can't find out how to do is to create my own Transaction, set a timeout, begin and then commit/rollback.
I have tried using:
UserTransaction utx = Transaction.instance();
utx.setTransactionTimeout(2000);
utx.begin();
But it is either ignored if a Transaction is already in progress or returns a javax.transaction.NotSupportedException if I annotate the method with @Transactional(NEVER)
Any help appreciated. Thanks.
As you know, Transaction Management is a cross-cutting concern. So it is not a good idea your code scattered about in modules where those concerns are not their primary concern.
If you are using a JTA UserTransaction in a non-EJB environment, so JTA is avaliable (Apache Tomcat does not support JTA).
1° rule
Seam transaction management is enabled by default for all JSF requests (Seam 2.0+).
I think Seam transaction management sounds better as Transactions managed by Seam. It means Seam takes cares, behind the scenes, of calling begin and commit. Seam plays the role of Transaction manager by using a Seam Transaction Manager
1° scenario: POJO + JTA avaliable (Apache Tomcat does not support JTA)
Transaction Manager used by Seam: org.jboss.seam.transaction.UTtransaction
Enabled by default in non-EJB environment (war) when JTA available (JBoss support JTA)
If you are using JPA EntityManager or Hibernate Session, you need to register them to allows Seam manage transaction boundaries
See 9.3. Seam-managed persistence contexts how to set up a Seam managed persistence context (Injected by using @In)
Then inject a EntityManager (EntityManager) or Session (Hibernate) by using @In (scoped to ScopeType.CONVERSATION)
@Name("businessService")
public class BusinessServiceImpl implementes BusinessService {
@In
private EntityManager entityManager;
public void doSomething() {
// You do not need to call entityManager().getTransaction().begin();
// because Seam Transaction Manager takes care of it
// By using proxies
// Therefore, if you call entityManager().getTransaction().begin()
// You will get IllegalStateException
// Some EntityManager operations persist, find etc
// You do not need to call entityManager().getTransaction().commit();
// because Seam Transaction Manager takes care of it
// By using proxies
}
}
Behind the scenes, Seam Transaction Manager enlist the EntityManager (JPA) or Session (Hibernate) in the active JTA UserTransaction, by calling joinTransaction method
2° scenario: POJO + RESOURCE_LOCAL (Either Hibernate or JPA) Transaction
Transaction Manager used by Seam (JPA): org.jboss.seam.transaction.EntityTransaction
Transaction Manager used by Seam (Hibernate): org.jboss.seam.transaction.HibernateTransaction
See 9.3. Seam-managed persistence contexts how to set up a Seam managed persistence context (Injected by using @In)
Behind the scenes, Seam Transaction Manager takes care of calling begin and commit in the underlying technology by using proxies
3° scenario: EJB
Transaction Manager used by Seam : org.jboss.seam.transaction.CMTTransaction
Enabled by default in EJB environment. Take care, in that case, Seam does not control container-managed transaction.
regards,
The way I'm currently working is like this:
//don't use @Transactional annotation
public void doStuff() {
UserTransaction userTx = (UserTransaction) org.jboss.seam.Component.getInstance("org.jboss.seam.transaction.transaction");
userTx.setTransactionTimeout(10 * 60); //set timeout to 60 * 10 = 600 secs = 10 mins
userTx.begin();
/*If entity manager is created before the transaction is started (ie. via Injection) then it must join the transaction */
entityManager.joinTransaction();
//do stuff
entityManager.persist(user);
entityManager.flush(); //logs will show an insert at this point
userTx.commit(); //or rollback()
}
But if a Transaction is already in progress and you want to join it then you use the userTx.isActive() etc
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