Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manual Transactions with Seam POJO

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.

like image 778
Damo Avatar asked Nov 24 '09 11:11

Damo


2 Answers

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,

like image 86
Arthur Ronald Avatar answered Sep 30 '22 14:09

Arthur Ronald


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

like image 35
Damo Avatar answered Sep 30 '22 12:09

Damo