11 Replies Latest reply on May 27, 2010 8:13 AM by shanikaweerapperuma

    Confused with Transaction Management

    shanikaweerapperuma
      Hi,

      I am new to this topic and bit confused as to what strategy exactly i am using since when i read about it there are so many strategies available. And i am not sure if I am using Seam managed transactions. I am using EJB3, seam, JSF with facelets in my application.

      I am injecting my entity manager as  @PersistenceContext (type=EXTENDED) to my stateful session bean. Accoding to documentation that means I am using Container Managed Persistance Context and not Seam Managed PC (since i dond't use @In to inject). Also I dont have any transactions attributes set to either to the class level or to the method level. So i think that means I am using Container Managed Transaction demarcation and expect the container to take care of my transactions. Please correct me if i am wrong.

      So with this, I am trying to see how to rolback the transaction that fails with an Application Exception.  Do i have to call setRollbackOnly method of the EJBContext interface before throwing my Exception? If so how do i get the Context object to call setRollbackOnly method?

      In my example below, i need to do a batch process. Either all objects in the ArrayList must get saved to DB or none if either one failes.

      @Stateful
      @Scope(ScopeType.SESSION)
      @Name("WFMaintenance")
      public class WFMaintenanceBean extends MyBean implements WFMaintenance

        @PersistenceContext (type=EXTENDED) 
          private EntityManager em;

        private ArrayList<Version> selectedVersions = new ArrayList<Version>();

        public void doBatchProcess(){
          try {
           for (Version v : selectedVersions)
               {
                  if (v.getItem() == null){

                     // Should I call setRollbackOnly() here?
                     throw new Exception("Error :Item of this version is null");
                  }
                 
                  // setting new values to v
                  // ....
               
                  em.merge(v);
                  em.flush();
               }

          } catch (Exception e) {     
               // Should I call setRollbackOnly() here as well?          
           e.printStackTrace();
          }

        }


      ...
      }

      Please help me to clarify this.
      Thanks

      Shanika
        • 1. Re: Confused with Transaction Management
          amitev

          The default transaction management strategy for seam is one transaction per JSF request. If you want to rely on the EJB container you have to explicitly disable the Seam transaction management in components.xml


          <core:init transaction-management-enabled="false" />
          

          • 2. Re: Confused with Transaction Management
            shanikaweerapperuma

            Thanks Adrian.  According to the Seam reference documentation,



            you can use conversation-scoped persistence contexts without Seam transaction management, and there are good reasons to use Seam transaction management even when you're not using Seam-managed persistence contexts. However, the two facilities were designed to work together, and work best
            when used together.

            In that case i can use extended persistence context and still use Seam transaction management. Please correct me if I am wrong.


            I am still wondering if my code above is correct, or do i have to include Transaction Attribute (javax.ejb.TransactionAttribute) ?  
            '
              @TransactionAttribute(TransactionAttributeType.REQUIRED)
               public void doBatchProcess(){
               ..
               ..
               }
            '


            I want to make sure that the transaction gets rolled back if any 'v' object in the for loop throws any exception during the batch process.


            -Shanika

            • 3. Re: Confused with Transaction Management
              amitev

              Hence you use an ejb class, the default behavior for it's method is @TransactionAttribute(TransactionAttributeType.REQUIRED) so you don't have to set it explicitly.

              • 4. Re: Confused with Transaction Management
                tagnegilles

                Hi Shanika


                I think you have to put this in the components.xml file




                <tx:ejb-transaction/>





                when you want to use both extended persistence context and Seam transaction management.

                • 5. Re: Confused with Transaction Management
                  shanikaweerapperuma

                  Thanks for the replies.


                  When I executed my batch process, i noticed that the 'v' objects that processed without any exeption got committed to the DB though some objects failed. I want the system to rollback instead.


                  Note : em.merge(v) is called for each v object in the loop through another method which actually does the modification to the object.


                  @Stateful
                  @Scope(ScopeType.SESSION)
                  @Name("WFMaintenance")
                  public class WFMaintenanceBean extends MyBean implements WFMaintenance
                  { 
                    @PersistenceContext (type=EXTENDED) 
                      private EntityManager em;
                  
                    private ArrayList<Version> selectedVersions = new ArrayList<Version>();
                  
                      @Begin (join=true)
                      public void doBatchProcess(){
                      try {
                           for (Version v : selectedVersions)
                           {
                              if (v.getItem() == null){
                  
                                 // Should I call setRollbackOnly() here?
                                 throw new Exception("Error :Item of this version is null");
                              }
                                 
                              modifyObject(v)          
                             
                           } 
                  
                      } catch (Exception e) { 
                           // Should I call setRollbackOnly() here as well? 
                           e.printStackTrace();
                      }
                  
                    }
                  
                  @Begin (join=true)
                  public void  modifyObject(object v){
                  
                          //.... modify v
                          ..
                          ..
                          em.merge(v); 
                          em.flush();
                  }
                  
                  
                  ...
                  }
                  



                  Must I call setRollbackOnly() in the catch block. If so how do i get the Context object to call setRollbackOnly method?


                  -shanika

                  • 6. Re: Confused with Transaction Management
                    shanikaweerapperuma

                    Please refer to this code segment instead. I missed throws Exception in the above for modifyObject(object v).


                    @Stateful
                    @Scope(ScopeType.SESSION)
                    @Name("WFMaintenance")
                    public class WFMaintenanceBean extends MyBean implements WFMaintenance
                    { 
                      @PersistenceContext (type=EXTENDED) 
                        private EntityManager em;
                    
                      private ArrayList<Version> selectedVersions = new ArrayList<Version>();
                    
                        @Begin (join=true)
                        public void doBatchProcess(){
                        try {
                             for (Version v : selectedVersions)
                             {
                                if (v.getItem() == null){
                    
                                   // Should I call setRollbackOnly() here?
                                   throw new Exception("Error :Item of this version is null");
                                }
                                   
                                modifyObject(v)          
                               
                             } 
                    
                        } catch (Exception e) { 
                             // Should I call setRollbackOnly() here as well? 
                             e.printStackTrace();
                        }
                    
                      }
                    
                    @Begin (join=true)
                    public void  modifyObject(object v) throws Exception{
                    
                            //.... modify v
                            ..
                            ..
                            em.merge(v); 
                            em.flush();
                    }
                    
                    
                    ...
                    }
                    




                    -shanika

                    • 7. Re: Confused with Transaction Management
                      kapitanpetko

                      For this to work, the exception has to get out of your method, so don't catch it. Also you need to throw an exception that extends  RuntimeException. Read up on EJB transaction management for more details.


                      HTH

                      • 8. Re: Confused with Transaction Management
                        shanikaweerapperuma
                        thanks HTH,

                        So I will have to throw an appliaction exeption without catching it.

                        I was refering to the bank example in Rolling Back a Container-Managed Transaction, at http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html. 
                        I was trying to refer to the source of InsufficientBalanceException but I couldn not find the source for the example. Do you know where i can refer the source from?



                        -shanika
                        • 9. Re: Confused with Transaction Management
                          shanikaweerapperuma
                          Hi,

                          Now the rollback works fine.
                          I created my own exception (MyException) with @ApplicationException with rollback set to true. I throw it out to the container. Also have logic in pages.xml to redirect to main page (toDoList.xhtml) in order to avoid redirection to Jboss Seam Debug page.

                          Now my issue is how to deal with any other exception that can get thrown other than MyException. At the moment I have a catch block that catches Exception e, which wraps it in a javax.ejb.EJBException and throws out to the container. The transaction rollsback, but how do i avoid it getting redirected to Jboss Seam Debug page. Should i do the same in pages.xml for EJBException as well, as in above case and redirect to some common error page in the system? This is since EJBException can get thrown from many other pages and not only from main page (toDoList.xhtml) of the system.

                          Appreciate your help.

                          '
                          @Stateful
                          @Scope(ScopeType.SESSION)
                          @Name("WFMaintenance")
                          public class WFMaintenanceBean extends MyBean implements WFMaintenance
                          {
                            @PersistenceContext (type=EXTENDED)
                              private EntityManager em;

                            private ArrayList<Version> selectedVersions = new ArrayList<Version>();

                              @Begin (join=true)
                              public void doBatchProcess(){
                              try {
                                   for (Version v : selectedVersions)
                                   {                          
                                      modifyObject(v)         
                                    
                                   }
                              } catch (MyException e) {                                  
                                  throw new MyException(e.getMessage());         
                                                  }
                              } catch (Exception e) {
                                   // Some other unexpected exception i.e a system exception
                                   throw new EJBException ("Transaction failed due to :" +e.getMessage());
                              }

                            }


                          public void  modifyObject(object v) throws MyException{

                                  //.... modify v
                                 
                                  if (v.getItem() == null){              
                                     throw new MyException("Error :Item of this version is null");
                                  }

                                  ..
                                  ..
                                  em.merge(v);
                                  em.flush();
                          }


                          ...
                          }
                          '

                          and in Pages.xml

                          '
                          <exception class="test.MyException">
                              <end-conversation/>                          
                              <redirect view-id="/toDoList.xhtml">
                              <message severity="error">#{org.jboss.seam.handledException.message}  </message>
                              </redirect>
                          </exception>
                          '
                          • 10. Re: Confused with Transaction Management
                            kragoth

                            For the sake of your users you should probably have a general catch all rule in your pages.xml


                            <exception>
                                <end-conversation />
                                <redirect view-id="/error/error.jsf">
                                    <message>Unexpected failure</message>
                                </redirect>
                            </exception>
                            



                            We basically have 2 types of exceptions in our system. Exceptions that we can handle (Validation exceptions etc) and then all other exceptions are handled by this rule.


                            I'm not sure how you can implement the rule for the exceptions that you can handle as I am not using the extended persistence context. We have a service layer (Spring) that marks our transaction boundary. But, I'm sure it would be possible.

                            • 11. Re: Confused with Transaction Management
                              shanikaweerapperuma
                              Thanks Tim,

                              I already have the rule in pages.xml as you have shown which will redirect to a common error page.  But what I wanted was to be able to redirect to the caller page (toDoList.xhtml) instead of redirecting to the common error page at this instance.  I managed to do it via throwing out MyException for any other Exception as well instead of EJBException since all i needed was a rollback and a redirection to my caller page.


                              '
                              } catch (Exception e) {                        

                                e.printStackTrace();                                 
                                throw new MyException("Transaction failed due to : " + e.getMessage());
                                                                             
                              }

                              '
                              -shanika