4 Replies Latest reply on Jun 29, 2007 3:51 PM by Chris Hane

    @Asynchronous / Conversations / Transactions Best Practices

    Chris Hane Novice

      I have an asynchronous method started from a SLSB. I know I can access the entitymanager in the async SLSB, is it possible to have Conversations or some type of fine grained transaction control.

      My async method takes a list of records and iterates over each record. I need to have the processing for each record occur in a separate transaction. If I don't use the method in the async mode, I can use Nested Conversations for each record (at least that is what I"m trying to get working now).

      It seems that I can not use the conversation context (even a new one) within an async method.

      I figure there has to be a way to have control over transactions, I just don't know enough about J2EE transaction control to figure it out. Any pointers would be helpful.

      Thanks,
      Chris....

        • 1. Re: @Asynchronous / Conversations / Transactions Best Practi
          Gavin King Master

          1. You can use standard EJB3 mechanisms for transaction demarcation, which certainly lets you have multiple transactions.

          2. An asynchronous method gets a a new temporary conversation context. It cannot access the conversation context from which it was spawned.

          HTH

          • 2. Re: @Asynchronous / Conversations / Transactions Best Practi
            Chris Hane Novice

            Thanks Gavin for the reply.

            I finally figured something out. Working with new technology is always fun, even if it is a bit frustrating. I'm very new to using EJB3 - in fact I switched to using it (from tomcat/hibernate) when seam was still in it's first releases (mainly cvs at that time) because I saw the power of the framework). But now I need to go back and learn some of the things the framework manages for me.

            I ended up putting

            @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

            on the class and method of the called method. Then in the method I create a new EntityManager. It's a little heavy handed but does the trick. I thought I could reuse the em for each transaction call; but couldn't figure it out. It works, just wondering if there was a better way. I tried a couple of things with UserTransaction but just didn't get it to work. Probably my fault.

            Thanks again,
            Chris....

            @Name(value="importSale")
            @Stateful
            @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
            public class ImportSale implements IImport {
            
             private EntityManagerFactory emf = null;
             private EntityManager em;
            
             private EntityManager txEntityManager(){
             return getEntityManagerFactory().createEntityManager();
             }
            
             private EntityManagerFactory getEntityManagerFactory(){
             if(emf == null) {
             try {
             return (EntityManagerFactory) Naming.getInitialContext().lookup("java:/customEntityManagerFactory");
             } catch(NamingException ne) {
             throw new IllegalArgumentException("EntityManagerFactory not found", ne);
             }
             } else {
             return emf;
             }
             }
            
             @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
             public void processXML(ParseFile parseFile, State state, Element record) {
             internalProcess(record);
             }
            
             private void internalProcess(Element record){
             try {
             em = txEntityManager();
             Contexts.getMethodContext().set("em", em); //added since DAO method access the em via
             //Contexts.lookupInAllStates(or
             // whatever the method is called)
             if(processXML(record)){
             } else {
             Transactions.setTransactionRollbackOnly();
             }
             } catch(Exception ex){
             try {
             Transactions.setTransactionRollbackOnly();
             } catch(Exception e) {
             throw new RuntimeException("Could not rollback erred record", e);
             }
             }
             }
            
             </snip rest>
            }
            


            • 3. Re: @Asynchronous / Conversations / Transactions Best Practi
              Gavin King Master

              Why not just use @PersistenceContext?

              • 4. Re: @Asynchronous / Conversations / Transactions Best Practi
                Chris Hane Novice

                Thanks - I'll give that a try. I didn't try since once I figured out how to use

                @In
                EntityManager em

                I didn't look at this piece again and I forgot about it. Now that I've been through a more in depth learning process, I won't forget about this again (actually I probably never really learned it the first time).

                Thanks for the pointer,
                Chris....