5 Replies Latest reply on Jun 1, 2009 4:41 PM by Israel Fonseca

    Seam and EJB Transactions

    Israel Fonseca Apprentice

      I want to understand better what happens with Seam Managed Transactions inside a EJB.



      When i use an SB method by default it's CMT, so a transaction starts in the beginning of the method calling and commit at the end. But at that time (invoke method phase of JSF), if i'm using seam-global-transactions (default behavior), i would already have a transaction running.


      So what happens them? EJB Container joins the current transaction at the beginning of the method call? And what happens after the method ending? It should be commited, but with seam it's suposed to be commited only in the end of the invoke method phase, so does the commit get supressed?


      Is that how it works? Or should i put BMT in my EJBs so that Seam can works alone?


      --


      Second question: If i use CMT with Seam with the use of @Transactional seam annotation that mimics the CMT inside a EJB, should i use the @TransactionManagement(TransactionManagementType.BEAN) in it (again it would be redundant to start two transactions at the beginning of the method).



      And to finish, how the @Transactional works with seam-global-transactions?


      Anyway, all my doubts are how the EJB-Transactions are handled by seam. I want to commit a transaction at the end of a method call (so i would propably use the @Transactional annotation) to handle the exception still in the invoke-method-phase.


      (In fact, what's the best practice to ignore EJB transactions and thinks only in Seam-Way of transaction handling?)


      Thks in advance,


      Israel

        • 1. Re: Seam and EJB Transactions
          Israel Fonseca Apprentice

          Just to make it easier to understand.


          How can i use seam-global-transactions, and commit the current transaction in the invoke-phase? I want this cause i dont want to redirect to another view to send the an error message, i just want to:




          public void peristPets(){
          try{
          em.persist(cat);
          em.persist(dog); // Hibernate Validator Error, or some other runtime error.
          } catch (ConstraintViolationException e){
           FacesMssage.add("Dog have 6 legs. Maximum of 4"); //It's an ajax request, no refresh, 
          //no redirect. Just a message in the screen.
           rollback(); //(clear the entityManager from the cat that was persisted.
          }
          
          listOfPets = listAllPetsFromDataBase(); // Dont bring the cat if an error happens,
          // cause the transaction was roll back.
          
          }
          




          All of this is in an long-running-conversation (entityManager is scoped to it), and even with an error i dont want to end it yet. I'm using conversation to use lot's of lazy loadings, so i still need the conversation running, and that's why i do need global transactions too.


          That's it. Is it possible?

          • 2. Re: Seam and EJB Transactions
            Jean Luc Apprentice

            I'm using conversation to use lot's of lazy loadings, so i still need the conversation running, and that's why i do need global transactions too.

            I don't think you need global transactions for that. You need an extended persistent context indeed. However, the automatic database transactions with which Seam wraps JSF requests (confusingly named 'global' transactions) will not help with this. The automatic transactions only serve to isolate those requests from other transactions and to perform a bit of performance optimization by having only one tx encompassing multiple requests (if they are) instead of several transactions, each adding its own overhead.





            All of this is in an long-running-conversation (entityManager is scoped to it), and even with an error i dont want to end it yet.


            If by 'error' you meant a transaction rollback, be aware that rolling back a transaction does not cause a rollback of the Java object in the persistent context but leaves an inconsistent state. To quote from the JPA spec:



            3.3.2 Transaction Rollback
            For both transaction-scoped and extended persistence contexts, transaction rollback causes all pre-existing managed instances and removed instances to become detached. The instances’ state will be the state of the instances at the point at which the transaction was rolled back. Transaction rollback typically causes the persistence context to be in an inconsistent state at the point of rollback. In particular, the state of version attributes and generated state (e.g., generated primary keys) may be inconsistent. Instances that were formerly managed by the persistence context (including new instances that were made persistent in that transaction) may therefore not be reusable in the same manner as other detached objects—for example, they may fail when passed to the merge operation.
            • 3. Re: Seam and EJB Transactions
              Israel Fonseca Apprentice

              Hmm, interesting. So if I do:


              em.persist(cat);
              em.persist(dog); //error


              Instances in the entity-manager get automatically detached (the cat for example). And about the transaction optimization. Queries to the database (from the lazy loading) needs a transaction? I always though that queries of any kind shouldnt need transactions cause it doesnt change the database anyway.

              • 4. Re: Seam and EJB Transactions
                Jean Luc Apprentice

                And about the transaction optimization. Queries to the database (from the lazy loading) needs a transaction? I always though that queries of any kind shouldnt need transactions cause it doesnt change the database anyway.

                Several comments here: at a lower level, there is always a transaction. When people talk about 'no transaction' they mean no transaction initiated by the application or by the container. In the absence of any such declaration (forget about Seam and CMT for a moment), multiple SQL statements sent to the database will each be wrapped in its own transaction so in fact there is more overhead with this. A reason to use an explicit transaction (via the app or the container) encompassing multiple statements is isolation from other transactions, especially for applications requiring a higher isolation level than READ COMMITTED. Without this encompassing transaction, if you have multiple SQL statements populating a page, it is possible that the statements do not see the same data if other transactions make modifications during this time.  There is also less overhead in establishing the only transaction then in the previous case.


                Lazy loading brings a different problem, however: multiple round-trips to the database. If you care about performance, then you want to avoid such a case and load the data in few queries with eager fetching. Extended persistence contexts are easy to abuse.


                For performance, you can make further optimizations by declaring the queries read-only so the JPA provider (at least Hibernate) will not store the snapshot used to detect changes (normally, when entities are loaded, Hibernate automatically stores a copy of what has been loaded so it can later check if an entity has been changed and thus requires an update at flush time. If you know that you will not modify those entities, this will save memory in the persistence context.

                • 5. Re: Seam and EJB Transactions
                  Israel Fonseca Apprentice

                  Thanks for the answer Jean, that's what i wanted to hear (read in fact.) :)