13 Replies Latest reply on Jun 7, 2010 6:40 AM by sathishavunoori

    Optimistic lock

    hfilho

      Hello all,


      I'm developing a project using Seam 2.1.2, JBoss AS 4.2.3, and JPA with Hibernate and PostgreSQL 8.4, with the core generated by seam-gen using the Seam CRUD Framework (Home/List). This is a plain WAR without EJBs but with the Seam managed persistence.


      We want optimistic locking, so I've added an integer field to the database tables and respective entities, and applied the @Version annotation to this field.


      To test the concurrency I'm accessing the page using 2 different browsers (Chrome and Firefox), and editing the same item on both browsers then committing on one and then on the other.


      The desired overall behavior is correct, it doesn't commit the second change, only doing one update for the first occurence, and incrementing the version field value, but it returns successfully, without throwing the OptimisticLockException.


      Any ideas why this is happening? I've even tried using the merge method in the EntityManager, but the result was the same as only changing the managed instance.


      Any help is much appreciated.



      Thanks,


      Heliton


        • 1. Re: Optimistic lock
          swd847

          Are you sure the exception is not being swallowed somewhere? Try stepping through with a debugger.

          • 2. Re: Optimistic lock
            jeanluc

            Also, enable show_sql and DEBUG or, better, TRACE for Hibernate see what actually goes on the wire to the db.


            As Stuart suggested, the exception may indeed be swallowed.

            • 3. Re: Optimistic lock
              hfilho

              Hey, thanks for the prompt replies.


              Yes, I'm sure it isn't being swallowed or lost. I have a try/catch for Exception around the flush call printing the stacktrace.


              Also I'd already tried debugging it. It returns OK, no errors or exceptions. The flow continues perfectly.


              Show-SQL is already turned on, and that's how I know it correctly only updates in the first case (that and checking the database row), only doing a select on the second to check the version value.


              Following your advice I turned on the TRACE, but couldn't find where it actually checks the version. Is it printed verbosely in the trace? All I could find was it doing an update on the version controller during the first call:




              2009-09-11 11:34:03,328 DEBUG [org.hibernate.engine.Versioning] Incrementing: 3 to 4
              2009-09-11 11:34:03,343 DEBUG [org.hibernate.persister.entity.AbstractEntityPersister] Existing version: 3 -> New version: 4




              During the second call it just says there are no updates and the dirty checking apparently comes up empty and it just moves on without any errors.


              Any other thoughts or suggestions?


              Thanks,


              Heliton

              • 4. Re: Optimistic lock
                clerum

                So if there are no updates how is this failing?


                The @Version works by only updating rows where the version it has matches the one in the DB. It will let you update the Entity in the session/conversation but when you try and persist the changes to the DB is where it should throw the error.

                • 5. Re: Optimistic lock
                  hfilho

                  when you try and persist the changes to the DB is where it should throw the error.


                  That's where it's failing. It doesn't throw an error, exception or even return an error message. On the contrary. It returns Ok, success, all good and jiggy baby.


                  This way I can't warn the user his changes weren't persisted because someone else changed the item while he was editing his copy. And that's bad.


                  Am I missing anything here? I added the @Version and @Column tag to an Integer field in an Entity, and the field exists in the database table. I load an instance of the item row, change it, join a transaction and flush the entity manager. Is there anything else I should do or configure?

                  • 6. Re: Optimistic lock
                    clerum

                    But your also not even seeing hibernate send the update to the database? If thats the case I don't think you have a versioning problem as it's not even getting far enough along to blow up on the update.


                    You may want to do a pastebin of the relevant code.

                    • 7. Re: Optimistic lock
                      jeanluc

                      During the second call it just says there are no updates and the dirty checking apparently comes up empty

                      Then this is what you need to investigate (and, if there is a problem indeed, it's something for the Hibernate forums so you may get more details there). You didn't get to the stage where an exception would be thrown because there was no update at all. Did you make the same change in both browsers? With TRACE logging, you should see the values bound to fields (just DEBUG is not enough).


                      • 8. Re: Optimistic lock
                        hfilho

                        Cody Lerum wrote on Sep 11, 2009 18:19:


                        But your also not even seeing hibernate send the update to the database? If thats the case I don't think you have a versioning problem as it's not even getting far enough along to blow up on the update.


                        Thanks for the replies. That was exactly what was happening. The entity was returning false on the dirty check (on the second browser I was trying to commit the original unedited values to test if it'd overwrite the new ones from the first browser) and therefore not generating the update. Upon changing a field in the second browser the  OptimisticLockException was thrown.


                        Along this line (and I know this is not a Hibernate forum but since Seam was made by some of the Hibernate people someone might know), is there any way to get a notification somehow (Exception, event, return code) that it didn't actually update anything cause it wasn't dirty?



                        Cheers,


                        Heliton

                        • 9. Re: Optimistic lock
                          titou09

                          If you not declare an exception handler in pages.xml, the OptimisticLockingException will be swallowed by seam.


                          In order to handle it, you have to declare an <exception> tag in page.xml (see the example code snippet in the doc that declare one for the OptimisticLockingExceptiono)


                          .. and then, you may face this JIRA: JIRA-4395


                          • 10. Re: Optimistic lock
                            hfilho

                            Denis Forveille wrote on Sep 13, 2009 13:51:


                            If you not declare an exception handler in pages.xml, the OptimisticLockingException will be swallowed by seam.


                            Hey Denis,


                            That's not really accurate. I got the exception without declaring it in the pages.xml, which is the desired behavior since I want to offer the user a chance to override or merge the changed data in the database if he knows his data is more important than what the concurrent user just put up, not just print an error message page (which is the default behavior implemented by seam-gen).


                            I'm now having to decide on whether I'll keep the CMT and find a workaround the ended transaction to be able to load the changed data from the database, or switch to BMT and be able to only rollback if there actually was a major problem.


                            Thanks for the reply anyway. Wasn't aware of that endless loop problem. Glad I still haven't upgraded to 2.2 yet. Guess I'll just wait for Seam 3.0 with JSF2.



                            Cheers,


                            Heliton

                            • 11. Re: Optimistic lock
                              titou09

                              Interesting.


                              You were saying in you first post that ... only doing one update for the first occurence, and incrementing the version field value, but it returns successfully, without throwing the OptimisticLockException. .


                              So now you now receive an exception?


                              Are you in a long running conversation?


                              How do you catch the OptimisticLockingException to display a valid message to the end user and give him a chance to respond ? with an interceptor?


                              Does your exception occurs during the automatic EJB/CMT commit ?  Or do you force a em.flush() before the end of the method and catch the exception ? Doing so will certainly capture most of the exceptions that can occur during commit but not all as many thing can happen between the flush and the commit...

                              • 12. Re: Optimistic lock
                                hfilho

                                You were saying in you first post that ... only doing one update for the first occurence, and incrementing the version field value, but it returns successfully, without throwing the OptimisticLockException. .

                                Read the other posts. I eventually solved it with help from the nice folk here.



                                So now you now receive an exception?

                                Are you in a long running conversation?

                                Yes to both.



                                How do you catch the OptimisticLockingException to display a valid message to the end user and give him a chance to respond ? with an interceptor?

                                No. My submit button calls a business method that has a try/catch around it. I set the flush mode to manual and when I call entityManager.flush(), there it is! :)
                                Then in the catch clause I queue a message in statusMessages and do some other business related processing, like preparing the context for the user to be able to decide whether to keep or discard his work.



                                Does your exception occurs during the automatic EJB/CMT commit ?  Or do you force a em.flush() before the end of the method and catch the exception ?

                                No, not using automatic. Was having way too much trouble with it, and I need/like having control over the transaction boundaries, specially since we like to have as much error handling as possible so the user is less troubled by common problems that can be solved in the background. That's why we're (supposedly) paid the big bucks ;)


                                • 13. Re: Optimistic lock
                                  sathishavunoori

                                  hi Heliton Filho,


                                  sorry for interrupting in middle.


                                  i am developing a seam application. In my application i need to develop Optimistic lock for some fields in entities using @version annotation of jpa. but how would i do this?
                                  i googled since two days but not getting a proper code block.


                                  So can you please show me some code and guide me to achive this?



                                  any help will be appreciated



                                  sathish