12 Replies Latest reply on Aug 8, 2013 6:33 PM by tony.herstell1

    Conversations and Container Managed Transactions

    tony.herstell1

      Is there a way to tell the container to align Transactions with a scope (in this case Conversation).

       

      I have callbacks with updated entities (from changes made to "parts" of it through primefaces components) and these serverside calls trigger the flushing of the update to the DB.

       

      I punted a guess with TransactionNotRequired and that didnt work.

       

      I want:

      1. To start a conversation
      2. To be able to accept all changes in the Conversation
      3. To "successfull" end the Conversation (from an "Update" button in the view) have the changes flushed to the DB

       

      It would be nice to force a conversation to be aborted but I dont see that that mehod exists yet.

       

      It would be hard to go with Business Scope of course as you cant have an Extended going THAT long; but then the business scope geneally has handled this differently!

       

      I will look more into turning flushMode to manual as well as a work round.


        • 1. Re: Conversations and Container Managed Transactions
          mkouba

          Hi Tony,

           

          I'm not completely sure I understand your use-case. However I'd avoid extended persistence context and use a conversation scoped bean to hold the changes instead... And merge detached entities or end conversation when the "update" button is pushed.

          • 2. Re: Conversations and Container Managed Transactions
            tony.herstell1

            Martin,

             

            Thx for replying.

             

            >> However I'd avoid extended persistence context

             

            Yea.. I tried that and had a lot of LIE's and there were other "naggings" from Weld that I should be using Extended (can't quite remember now - writeen 20K lines in last few weeks so it's all a blur)...

            So; I think in my case better to stay with extended as its working fine.

            I am using JBoss 7.1.1.Final so my Weld is probably quite out of date now.

             

            >> conversation scoped bean to hold the changes instead

             

            I do have a conversation scoped "controller" bean, but I was outjecting the actual entity to have the updates applied; hence changes were being pushed by JPA(Hibernate) immideatly it saw a change in the Entity.

             

            But what makes sense (to me):

            1. Set flushMode to manaul and only flush when I .end the conversation (This should be standard behaviour if you are using Conversation scoope as "does ANYTHING else make sense?")

            OR

            2. Copy the Entity values to a LOCAL (unmanaged) bean in the conversation scoped controller and do the updates to that just before calling .end on the conversation.

             

            I like 1. as:

            it leaves all the heavy lifting to JPA (Hiberante) to roll back the changes its made to its cache... (I just hope it does this - pretty sure it worked fine in Seam!)

            If I have touched numersous entites then its a LOT easier to handle this (just imagine having to create whole trees of copied entities and managing that!)

             

            I will try 1. when I get past the Create/Update screens I have to compelte for 5 more entities.


            • 3. Re: Conversations and Container Managed Transactions
              tony.herstell1

              To try to clear up what I said about Conversations...

               

              This may sound nieve... but this is my basic understanding of the how Conversation "should" (and did as far as I know) work based on my expereince with Seam...

               

               

              A conversation wraps an atomic piece of "work" (in the real world) and this may involve 10's of screens and 1000's of Entity changes.

               

              If at the end of the Conversation you are happy with the changes you end the conversation and... all the updates should get pushed to the Database (and systems)...

               

              if you are not happy you should abort the conversation and... nothing should be sent to the Database (and systems)

                  NOTE: I can see no way to .abort() a conversation in Weld so I guess you just have to let it time out...

               

              Now by adding VerionForOptomisticLock on your entities you should "trip" if someone has sneaked in and updated anything on the DB and it's up to you to handle this (Sorry user.. try again.. ).

               

              ...

               

              Conversations are just Baby version of the Business Scope; which even allows you to wander away and come back to finish a "business task" a few days later... and this is handled all quite differently as you cannot "hang onto" references to objects in memory... Go DROOOooools and jBPM for that...   (Bough the book and need to read it at some point).

               

               

              Mostly, using a real App Server, you can ignore all this plumbing as its all handled for you (Scopes and Transactions [a bit of work for XTA Transactions I guess])... and this is why we use App Servers!

              • 4. Re: Conversations and Container Managed Transactions
                tony.herstell1

                I do have session scoped lists of "things" (entities mostly) that my conversations update...

                 

                When my conversations are complete I want to (not quite got it workign yet as Weld moans about something to do with passing entities before some transaction boundary or summat) send an event with the Entity to my session beans to get them to update their Store.

                 

                With all this going, I have VERY few accesses to the Datatbase... obviously... at the expense of memory, but... it's the Database that never scales and is the bottleneck aint it?

                • 5. Re: Conversations and Container Managed Transactions
                  luksa

                  Tony Herstell wrote:

                   

                  A conversation wraps an atomic piece of "work" (in the real world) and this may involve 10's of screens and 1000's of Entity changes.

                   

                  If at the end of the Conversation you are happy with the changes you end the conversation and... all the updates should get pushed to the Database (and systems)...

                   

                  if you are not happy you should abort the conversation and... nothing should be sent to the Database (and systems)

                      NOTE: I can see no way to .abort() a conversation in Weld so I guess you just have to let it time out...

                   

                  No, a *transaction* wraps an atomic piece of work, a *conversation* is just a context the transaction lives in. You can have many consecutive transactions in the scope of a single conversation, if you want.

                   

                  A conversation has a beginning and an end. There is no notion of "aborting a conversation". But, you can of course rollback or commit the transaction just before you end the conversation.

                  • 6. Re: Conversations and Container Managed Transactions
                    tony.herstell1

                    Marko,

                    Great reply and all this helps my understanding.

                    I have not added any @Trasaction annotation for years as I just rely on the container to manage all this for me... I got this "lazy" as, I believe, that Seam just frigged the Transaction to match the Conversation scope (as it makes sense).

                    But I agree that you can have multiple Transactions inside a conversation if you choose to... and going "bean managed" makes sense here.

                    I believe in the old "Seam" you could align these "sub transations" with nested Conversations but I never did that so don't quote me on that..

                    Thanks for replyig.

                     

                    • 7. Re: Conversations and Container Managed Transactions
                      mkouba

                      If I recall correctly the Seam 2 "managed transactions" feature tied the extended persistence context (Hiberante/JPA) to a conversation context. This is comfortable to use (LazyInitializationException etc.) as long as there are no performance issues - may become a hell for real apps under load (HTTP session size may easily reach several MBs).

                       

                      Also keep in mind that CDI does not know a concept of outjection (see for example https://community.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies).

                       

                      Good luck !

                      • 8. Re: Conversations and Container Managed Transactions
                        tony.herstell1

                        > may become a hell for real apps under load (HTTP session size may easily reach several MBs).

                        Noted.

                        Thx.

                         

                        > Also keep in mind that CDI does not know a concept of outjection (see for example https://community.jboss.org/blogs/stuartdouglas/2010/10/12/weld-cdi-and-proxies).

                        Yes.. I found that... ... had me confused for ages.

                         

                           // DON'T let any Entities be Proxied by WELD so just use class local.
                           // According to this definition, JPA entities are technically managed beans.
                           // However, entities have
                           // their own special lifecycle, state and identity model and are usually
                           // instantiated by JPA or using
                           // new. Therefore we don't recommend directly injecting an entity class. We
                           // especially recommend
                           // against assigning a scope other than @Dependent to an entity class, since
                           // JPA is not able to
                           // persist injected CDI proxies.
                           private Site siteToBeAffected;
                        

                         

                        I go "native"...

                        Will look at your post and digest.



                        • 9. Re: Conversations and Container Managed Transactions
                          tony.herstell1

                          Martin,

                           

                          >>> If I recall correctly the Seam 2 "managed transactions" feature tied the extended persistence context (Hiberante/JPA) to a conversation context. This is comfortable to use (LazyInitializationException etc.) as long as there are no performance issues - may become a hell for real apps under load (HTTP session size may easily reach several MBs).

                           

                          I think the point was to make Seam a pleasure to use for new people (It was said that using seam means you never have a LIE and that certainly attracted me to it).

                           

                          Never used technology so easy to pick up before as Seam; by chapter 3 I was already altering the "example" tutorial to do stuff I needed and never looked back... I dont think I ever reached the end of the manual as by Chapter 6 it was all "reference" stuff anyhow!

                           

                          By the time you are hooked on the "beautiful" technology you can figure out (or read) how to work round the "tied extended" if you have concerns (like Big data etc.).

                           

                          What do you think...

                          • 10. Re: Conversations and Container Managed Transactions
                            mkouba

                            Yep, the thing is the easiest path is not always the best one

                            • 11. Re: Conversations and Container Managed Transactions
                              tony.herstell1

                              Something that works (but must be wrong) is to detach the object when I enter the conversation (for update)

                               

                              this.em.detach(yield);
                              

                               

                              then I can update it as much as I like and, as its not managed, it won't flush to DB...

                               

                              Most updates are via this method....

                                 public void handleHoneyKindChange() {
                                    this.logger.info("> handleHoneyKindChange");
                                    this.logger.info("< handleHoneyKindChange");
                                 }
                              

                              It does nothing but primefaces ajax calls it (has to have it) to handle an update to the Dom...

                                             <p:selectOneMenu id="yieldHoneyKindCU" value="#{yield.honeyKinds.honeyKind}" required="true" requiredMessage="#{messages.required}">
                                                <f:selectItem itemLabel="#{messages.select_one}" itemValue="" />
                                                <f:selectItems value="#{honeyKindOptions.honeyKindValues}" var="honeyKind" itemValue="#{honeyKind}" itemLabel="#{honeyKind.inlLabel}" />
                                                <p:ajax update="yieldPanelCU" listener="#{controller[handleHoneyKindChange]}" />
                                             </p:selectOneMenu>
                              


                               

                              then I can, when the final "commit button" is pressed...  re-read the object, merge it, and then persist it.

                               

                              Sound awful... but seems to work.

                               

                              Yield yieldToBeMergedInto = (Yield) this.em.createQuery(YieldDatabaseQueries.GET_YIELD_BY_ID_QUERY).setParameter("id", yield.getId()).getSingleResult();
                              this.em.merge(yield);
                              

                               

                              This sounds wrong on so many levels...

                              I am hacking the EntityManager to detach a perfectly good entity that is linked to other entities...

                               

                              I WANT to use flushmode of Manaul, but can't as its been removed from JPA...

                               

                              google shows a lot of people are struggling with this... (see the view on this thread already!)

                              • 12. Re: Conversations and Container Managed Transactions
                                tony.herstell1

                                I was advised to try this (Thx to Joel Crisp and Jason Porter)...

                                 

                                I just had to reach through em all the way into Hibernate to set it.

                                 

                                 

                                public String init(CRUDMode crudMode, Yield yield) {
                                      this.logger.info(">>>init with CRUD Mode:" + crudMode + " and Yield: " + yield.getId());
                                ..
                                
                                      } else if (this.getCRUDMode() == CRUDMode.UPDATE) {
                                         navigationToReturn = "pretty:updateYield";
                                         Session session = this.em.unwrap(Session.class);
                                         session.setFlushMode(FlushMode.MANUAL);
                                
                                

                                 

                                then.... later (after all the server/client round trips)... I finally press the "Confirm" Update button...

                                 

                                   public String updateYield(Yield yield) {
                                      this.logger.info(">>> updateYield " + yield.getId());
                                ...
                                
                                      this.em.merge(yield);
                                      this.em.flush(); // See FlushMode of Manual as we enter the Update.
                                
                                

                                 

                                Had to add Hibernate to POM... to access

                                   import org.hibernate.FlushMode;

                                   import org.hibernate.Session;

                                 

                                 

                                 

                                <dependency>
                                
                                         <groupId>org.hibernate</groupId>
                                         <artifactId>hibernate-core</artifactId>
                                         <version>4.0.1.Final</version>
                                      </dependency>
                                

                                 

                                 

                                This is a Hibernate Specific solution.

                                 

                                Looks like it works (SO FAR).