1 2 3 Previous Next 41 Replies Latest reply on Aug 27, 2009 8:36 PM by asookazian

    Transactional propagation types

    asookazian

      I have a web service client call and local db CRUD operations in one business method.  So I'm trying to turn off tx support for a particular method (I'm using @Transactional at class level).


      When I use this:


      @Transactional(TransactionPropagationType.NEVER)


      I get this:
      Caused by: java.lang.IllegalStateException: Transaction active on call to NEVER method


      And Seam's tx mgmt does not support NOT_SUPPORTED from EJB3.  Even Spring's tx mgmt and propagation types is more robust than Seam's.


      What is the course of action here other than using EJB3 now (I'd like to stick with WAR for hot deployment advantage for a while and then upgrade to EAR)?


      Here are the available TransactionPropagationType enum constants:


      MANDATORY          
      NEVER          
      REQUIRED          
      SUPPORTS

        • 1. Re: Transactional propagation types

          So... let see:


          Option 1) Move your method to another class without @Transactional at class level and keep it as a WAR (I might take you around... 10 minutes?)


          Option 2)  Reorganize your project in to an sluggish and cumbersome EAR (It may take you a whole day, and that without the extra productivity loss your are going to have to live with now that your project is sluggishly slow)


          It is such a hard choice ;-)

          • 2. Re: Transactional propagation types
            israel.bgf

            Strange, the @Transactional(TransactionPropagationType.NEVER) should override the @Transactional put in the class. Anyway, aren't you using seam-global-transactions? As far I know the @Transactional annotations are ignored when using global transactions.

            • 3. Re: Transactional propagation types
              asookazian

              The context of this use case is as follows.  A LRC is begun when the user navigates to the page in question:


              <page view-id="/EquipmentProcessingView.xhtml">
                       <begin-conversation join="true" flush-mode="manual"/>
                     ....
              </page>



              This may eventually change, I'm just experimenting with starting a LRC immediately when user first navigates to the page.


              There is an @Begin(join=true) on one of the @Factory methods which probably is not necessary if the LRC is configured in pages.xml.


              @Begin(join=true)  
                   public void getCustomerInformation(){...}



              There is @Transactional at the class level so that means by default all business methods require a tx.  I can probably remove this and annotate each business method accordingly.


              But really what's happening is that a tx is already running when the business method annotated with @Transactional(TransactionPropagationType.NEVER) is executed.  This would be illegal as per JSR220 as well.


              I'm not moving back to EJB yet.  I got the Seam interceptor working for my ProfilingInterceptor which was cool, now I know how long my business methods take to execute (again!)  thx.

              • 4. Re: Transactional propagation types
                asookazian

                Israel Fonseca wrote on Aug 25, 2009 19:01:


                Strange, the @Transactional(TransactionPropagationType.NEVER) should override the @Transactional put in the class. Anyway, aren't you using seam-global-transactions? As far I know the @Transactional annotations are ignored when using global transactions.


                Sorry, being lazy.  How would I know if I'm using Seam global tx's or not?  I think you have to configure manually to turn them off, no?

                • 5. Re: Transactional propagation types
                  israel.bgf
                  "Note, however, that the @Transactional annotation is irrele-
                  vant during a JSF request when using Seam global transactions.
                  "

                  That's from Seam in Action. And to deactivate the global-transactions you have to put this in components.xml:

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

                  It's true by default so that's your case. But that's make the things more strange, because if the @Transactional should be ignored, why is it throwing an exception?

                  Strange...
                  • 6. Re: Transactional propagation types
                    asookazian

                    This is what I have in components.xml:


                    <core:init debug="@debug@" jndi-pattern="@jndiPattern@"/>




                    Seam wraps a built-in method interceptor around components that contain
                    the @Transactional annotation, which interprets this annotation and drives the
                    transaction accordingly. Note, however, that the @Transactional annotation is irrelevant
                    during a JSF request when using Seam global transactions.


                    I'm wondering if the underlined above is a typo in the book.  It doesn't seem to be true in my case definitely.  And I believe DAllen goes on to state that turning off global tx's is not a good idea either.

                    • 7. Re: Transactional propagation types
                      swd847

                      I think what he meant was that @Transactional is irrelevant for the most common case (i.e. when you want to mark a method as running inside a transaction).


                      NEVER and global transactions are not compatible, global transaction means there is always a transaction, which means that methods marked with NEVER will always throw an exception.


                      This is why I use ejb3.

                      • 8. Re: Transactional propagation types
                        israel.bgf

                        I really like Seam, but i cant tell you: I always disable the global transactions. I don't like the fact to do a redirect just to show an error message, I want an message triggered by ajax, and global transactions don't give this control. And i'm still reluctant about the conversation context when a lot of data is involved, tons of results handling in the persistence context looks a little dangerous when a lot of users are using the system at the same time, i'm really well with the transactional persistence context, it's not difficult do handle LIEs anyway.

                        • 9. Re: Transactional propagation types

                          Stuart Douglas wrote on Aug 26, 2009 13:05:


                          NEVER and global transactions are not compatible, global transaction means there is always a transaction, which means that methods marked with NEVER will always throw an exception.

                          This is why I use ejb3.


                          So, the annotation NEVER means : You will NEVER be able to execute this method if there is a transaction


                          While NOT_SUPPORTED  means: While you run this method, if there is a running transaction, I'll susppend it, and resume it after the method has finished. (Not a very intuitive name)



                          More info here.


                          Now, what I really would like to know, is why do you ever want to suspend a transaction? and more particularly: why (exactly) do you want to suspend a transaction? What concrete feature or behavior in your system makes you need that?.


                          (I have built several systems I still have not needed to do so, so I am extremely curious on why would you want to do it)


                          • 10. Re: Transactional propagation types

                            According to EJB docs , NOT_SUPPORTED should be used:



                            Transaction Attributes in the JEE Tutorial:

                            [...]for methods that don’t need transactions. Because transactions involve overhead, this attribute may improve performance.


                            So... that is what it is for? better performance? are you actually experiencing slower performance and trying to optimize? (because if that is the purpose of NOT_SUPPORTED, any performance advantage you get by using it will totally disappear thanks to huge performance penalty EJBs will bring in your application. Don't fall the hell of premature optimization.

                            • 11. Re: Transactional propagation types
                              israel.bgf

                              At least with plain EJB, if you suspend a transaction, the entities retrieved by a query are NOT going to be in the persistence context, and it's going to give you a performance boost (the provider don't lost it time managing the result list).

                              • 12. Re: Transactional propagation types
                                asookazian

                                I have a functional requirement as follows:


                                insert record into remote db via web service call


                                insert record into local db


                                Do not treat as a distribute tx (i.e. if one or the other fails if SQLServerException is thrown or network error, etc. do not rollback the other one)


                                So if there is already a tx running, then this business method is called, I need to suspend the tx, execute the method with both inserts, then continue tx.


                                I could probably create two methods instead of one, but I am considering this one logical unit of work w/o tx.

                                • 13. Re: Transactional propagation types

                                  Israel Fonseca wrote on Aug 26, 2009 18:11:


                                  At least with plain EJB, if you suspend a transaction, the entities retrieved by a query are NOT going to be in the persistence context,


                                  Interesting... lets review what is a persistency context:



                                  Persistence context


                                      A persistence context is a set of entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle is managed by a particular entity manager. The scope of this context can either be the transaction, or an extended unit of work.

                                  I might be understading it wrong, but it seems to me that a PersistencyContext is an abstract concept that pretty much maps 1 to 1 to an entityManager intance (I of course might be wrong, if I am please correct me) now you say that the entities retrieved by a query are NOT going to be in the persistence context, I guess that should be (after correction): the entities retrieved by a query are going to be in a DIFFERENT persistence context... Now...what is the speed advantage in that? that since it is a new persistence context it has less entities loaded in it?




                                  and it's going to give you a performance boost (the provider don't lost it time managing the result list).


                                  And exactly how many nanoseconds per entity  am I going to get? or maybe nanoseconds per query? how many entities (or queries) do I need to be doing to make it significant?

                                  • 14. Re: Transactional propagation types
                                    asookazian

                                    So I did the following in components.xml:


                                    <core:init debug="@debug@" jndi-pattern="@jndiPattern@" transaction-management-enabled="false"/>



                                    And this to my Seam component:


                                    @Name("equipmentProcessingView")
                                    @Scope(ScopeType.CONVERSATION)
                                    @ProfilingThisClass
                                    //@Transactional
                                    public class EquipmentProcessingViewAction implements Serializable {
                                    ...
                                    
                                           @Transactional(TransactionPropagationType.NEVER)  //don't use local tx b/c we want either process to complete even if the other throws an exception     
                                         @End
                                         public void apply() {
                                              
                                              progressBarWebService.startProcess();  //web service remote db insert
                                              progressBarLocalDB.startProcess();
                                              
                                              insertStatusAndErsNote();  //local db inserts
                                              
                                              //force re-fresh of the status @DataModels
                                              customerEquipmentOneStatusList = null;
                                              customerEquipmentOtherStatusesList = null;
                                              
                                              currentlySelectedEquipmentBean = null;
                                              icomsNote = null;
                                              ersNote = null;
                                              selectedListValueForNewStatus = null;
                                              
                                              
                                         }
                                    
                                    }



                                    @SuppressWarnings("unchecked")
                                         //@Transactional <-- only applies for public business methods
                                         private void insertStatusAndErsNote(){
                                              //we need to insert into two tables: EquipmentRecoveryStatusChangeLog and EquipmentNotes
                                              /*
                                                        a.     Status: EquipmentRecoveryStatusChangeLog: equipmentrecoveryid, equipmentstatusid, iscurrent 
                                                                       (1 = latest, 0 = older, requires insert and update existing record with 1 to 0)
                                                        b.     ERS Note: EquipmentNotes
                                                        */
                                    
                                              Long equipmentRecoveryId = currentlySelectedEquipmentBean.getEquipmentRecoveryId();
                                              EquipmentRecovery equipmentRecovery = entityManager.find(EquipmentRecovery.class, equipmentRecoveryId);
                                              
                                              int equipmentStatusId = selectedListValueForNewStatus.getCode();
                                              EquipmentStatus equipmentStatus = entityManager.find(EquipmentStatus.class, equipmentStatusId);
                                              
                                              Date today = new Date();
                                              
                                              //update existing record in EquipmentRecoveryStatusChangeLog which has isCurrent = 1          
                                              List<EquipmentRecoveryStatusChangeLog> ersclList = entityManager.createQuery("select erscl "+
                                                                                                                                                  " from EquipmentRecoveryStatusChangeLog erscl "+                                                                                                              
                                                                                                                                                  " where erscl.equipmentRecovery.equipmentRecoveryId = :equipmentRecoveryId "+
                                                                                                                                                  " and erscl.isCurrent = 1")                                                                                          
                                                                                                                              .setParameter("equipmentRecoveryId", equipmentRecoveryId)
                                                                                                                              .getResultList();
                                              
                                              if (ersclList != null && ersclList.size() > 0){
                                                   EquipmentRecoveryStatusChangeLog myErscl = ersclList.get(0);
                                                   myErscl.setIsCurrent(false);               
                                                   entityManager.flush();
                                              }
                                              
                                              //insert record in EquipmentRecoveryStatusChangeLog
                                              EquipmentRecoveryStatusChangeLog erscl = new EquipmentRecoveryStatusChangeLog(                    
                                                                                                          equipmentStatus,
                                                                                                          equipmentRecovery,
                                                                                                          true
                                                                                                          ); 
                                              entityManager.persist(erscl);          
                                              entityManager.flush();
                                              
                                              List<ListValue> listValueList = entityManager.createQuery("select lv "+
                                                                                                                    " from ListValue lv "+
                                                                                                                    " where lv.list.listName = :listName "+
                                                                                                                    " and lv.listValue = :listValue ")
                                                                                                     .setParameter("listName", NOTE_TYPES)
                                                                                                     .setParameter("listValue", USER)
                                                                                                     .getResultList();
                                              
                                              if (listValueList != null && listValueList.size() > 0){
                                                   ListValue myLV = listValueList.get(0);
                                                   String noteTypeCode = Integer.toString(myLV.getCode());
                                                   
                                                   //insert record into EquipmentNotes
                                                   EquipmentNotes equipmentNotes = new EquipmentNotes(equipmentRecovery,
                                                                                                                    ersNote,
                                                                                                                    noteTypeCode 
                                                                                                                    );
                                                   
                                                   entityManager.persist(equipmentNotes);
                                                   entityManager.flush();
                                              }
                                              
                                              
                                              
                                         }



                                    I get this:


                                    09:36:56,649 ERROR [ExceptionFilter] exception root cause
                                    javax.faces.FacesException: #{equipmentProcessingView.apply}: javax.persistence.TransactionRequiredException: no transaction is in progress
                                         at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118)
                                         at javax.faces.component.UICommand.broadcast(UICommand.java:387)
                                         at org.ajax4jsf.component.AjaxActionComponent.broadcast(AjaxActionComponent.java:55)
                                         at org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:321)
                                         at org.ajax4jsf.component.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:296)
                                         at org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:253)
                                         at org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:466)
                                         at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
                                         at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
                                         at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
                                         at javax.faces.webapp.FacesServlet.service(FacesServlet.java:265)
                                         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
                                         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                                         at jcifs.http.NtlmHttpFilter.doFilter(NtlmHttpFilter.java:125)
                                         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                                         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                                         at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
                                         at org.jboss.seam.debug.hot.HotDeployFilter.doFilter(HotDeployFilter.java:68)
                                         at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                                         at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)
                                         at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                                         at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
                                         at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                                         at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
                                         at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                                         at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:178)
                                         at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
                                         at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:368)
                                         at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:495)
                                         at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60)
                                         at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                                         at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58)
                                         at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                                         at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
                                         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                                         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                                         at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
                                         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                                         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                                         at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
                                         at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
                                         at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:182)
                                         at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
                                         at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
                                         at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
                                         at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
                                         at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
                                         at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
                                         at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:241)
                                         at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
                                         at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:580)
                                         at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
                                         at java.lang.Thread.run(Thread.java:595)
                                    Caused by: javax.faces.el.EvaluationException: javax.persistence.TransactionRequiredException: no transaction is in progress
                                         at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
                                         at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
                                         ... 52 more
                                    Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
                                         at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:301)
                                         at org.jboss.seam.persistence.EntityManagerProxy.flush(EntityManagerProxy.java:90)
                                         at com.cox.ers.session.EquipmentProcessingViewAction.insertStatusAndErsNote(EquipmentProcessingViewAction.java:151)
                                         at com.cox.ers.session.EquipmentProcessingViewAction.apply(EquipmentProcessingViewAction.java:108)
                                         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                                         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                                         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                                         at java.lang.reflect.Method.invoke(Method.java:585)
                                         at org.jboss.seam.util.Reflections.invoke(Reflections.java:21)
                                         at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:31)
                                         at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56)
                                         at com.cox.ers.utils.ProfilingInterceptor.profile(ProfilingInterceptor.java:22)
                                         at sun.reflect.GeneratedMethodAccessor392.invoke(Unknown Source)
                                         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                                         at java.lang.reflect.Method.invoke(Method.java:585)
                                         at org.jboss.seam.util.Reflections.invoke(Reflections.java:21)
                                         at org.jboss.seam.intercept.Interceptor.aroundInvoke(Interceptor.java:177)
                                         at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:72)
                                         at org.jboss.seam.core.BijectionInterceptor.aroundInvoke(BijectionInterceptor.java:46)
                                         at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
                                         at org.jboss.seam.persistence.ManagedEntityIdentityInterceptor.aroundInvoke(ManagedEntityIdentityInterceptor.java:48)
                                         at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
                                         at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:31)
                                         at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
                                         at org.jboss.seam.core.ConversationInterceptor.aroundInvoke(ConversationInterceptor.java:56)
                                         at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
                                         at org.jboss.seam.transaction.TransactionInterceptor$1.work(TransactionInterceptor.java:38)
                                         at org.jboss.seam.util.Work.workInTransaction(Work.java:41)
                                         at org.jboss.seam.transaction.TransactionInterceptor.aroundInvoke(TransactionInterceptor.java:32)
                                         at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
                                         at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:42)
                                         at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
                                         at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107)
                                         at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:166)
                                         at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:102)
                                         at com.cox.ers.session.EquipmentProcessingViewAction_$$_javassist_7.apply(EquipmentProcessingViewAction_$$_javassist_7.java)
                                         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                                         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                                         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                                         at java.lang.reflect.Method.invoke(Method.java:585)
                                         at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:329)
                                         at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:342)
                                         at org.jboss.el.parser.AstPropertySuffix.invoke(AstPropertySuffix.java:58)
                                         at org.jboss.el.parser.AstValue.invoke(AstValue.java:96)
                                         at org.jboss.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276)
                                         at com.sun.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:68)
                                         at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
                                         ... 53 more




                                    If you refer to persist() method in EntityManager.java you can see the javadocs clearly mention that persist throws javax.persistence.TransactionRequiredException if there is no transaction.

                                    source: http://weblogs.java.net/blog/ss141213/archive/2005/12/entitymanagerpe_1.html


                                    That's interesting, I did not know that.  Pretty much means that JPA cannot operate in auto-commit mode I guess if you want to save data to db.  Seems to have nothing to do with the flushMode either.


                                    Anyways, in EJB, a business method is typically defined as a public method that is exposed in a local/remote interface.  Seam JavaBean components do not have to implement any interfaces, so how does the Seam container know which methods in the JavaBean component are business methods (wild guess: those marked public?)  So that means private methods join the tx of their parent public method.


                                    So this is getting overly-complicated and messy.  I want to keep the hot deploy with JavaBeans but also need the tx flexibility for my functional requirement.


                                    Am I missing something here or what?  And out of curiosity, how would you implement this, from a tx-al perspective, for this requirement if you used session beans?



                                    1 2 3 Previous Next