Question

I have a web application made with Tapestry5 (java webframework) and Hibernate. Now I'm trying to add optimistic locking. So I added a version attribute and the optimistic locking works, so that was easy and fast.

But as my web application works with "session-per-request" pattern, I'm not sure what's the best way of making use of this optimistic locking.

What happens:

UserA opens page with form which is loaded with values from entityA (version 1).

UserB opens page with form which is loaded with values from entityA (version 1).

UserA changes some values and submits the form. -> New request retrieves entityA (version 1) and commits changes (entityA is now version 2)

UserB changes some values and submits form. -> New request retrieves entityA (version 2) and commits changes (entityA is now version 3)

What should happen

Changes of UserB should not be committed. But because of session-per-request pattern the time window where optimistic locking error of Hibernate can occure is reduced to the timespan of just from the new request after the submit to the commit, which is not the desired result.

Possible solutions

After some research I found the following:

  • Add a hidden field to the form with the entities version

I could use this value to set the version of the entity before the commit, but Hibernate documentation doesn't recommend setting this value. Also it only works if the entity is detached and reattached, because else the manually set version value is ignored by Hibernate.

Secondly I could use this version value to do a manual check if the version, when the form was rendered, is the same as the version of the entity loaded in the request on submit. Then throw a OptimisticLockingException myself if needed.

  • Put the detached entity into HttpSession, so I don't have to load it again on submit

Conclusion

These methods work, but don't seem very practical to me and easy to make errors on. So I'm wondering how other people implement this problem.

Était-ce utile?

La solution

I ended up implementing the following:

  • Add a hidden field to the form with the entities version
  • Use of form dto objects
  • Attaching these dto objects to the httpsession (conversational state across multiple requests)
  • Manual version check between dto and actual object

Autres conseils

When you detach a persistent entity just to transfer it to the web layer, as an example create DTO to transfer objects to the web layer. in that case we will transform Entity objects into the DTO objects using getters and setters.

If you need to maintain the concurrency control with Optimistic locking, you have to maintain the version number in your application (it's different from manually setting the version number). Otherwise there is no way we can instruct hibernate what was the old version of the loaded record. In hibernate documentation it says "Keep the disconnected Session close to the persistence layer. Use an EJB stateful session bean to hold the Session in a three-tier environment. Do not transfer it to the web layer, or even serialize it to a separate tier, to store it in the HttpSession. ", But all the environments do not have EJB stateful session beans in business layer. In that case we have to maintain the version number.

As long as you can maintain the version, you do not need to manually check the version in the program, it is efficient if you let hibernate to do that, because you cannot predict the depth of your object hierarchy.

So what you can do is you have to set the version again to the persistent entity if you use detached objects in the web layer, Then hibernate will take care of the Cocurrency Control.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top