Hibernate entities stored as HttpSession attribute values
I'm dealing with a legacy Java application with a large, fairly messy codebase. There's a fairly standard 'User' object that gets stored in the HttpSession between requests, so the servlets do stuff like this at the top:
HttpSession session = request.getSession(true);
User user = (User)session.getAttribute("User");
The old user authentication layer (which I won't describe; suffice to say, it did not use a database) is being replaced with code mapped to the DB with Hibernate. So 'User' is now a Hibernate entity.
开发者_如何学PythonMy understanding of Hibernate object life cycles is a little fuzzy, but it seems like storing 'User' in the HttpSession now becomes a problem, because it will be retrieved in a different transaction during the next request. What is the right thing to be doing here? Can I just use the Hibernate Session object's update() method to reattach the User instance the next time around? Do I need to?
Assuming that you are creating a new hibernate session for each request-response cycle, it is possible to merge a detached object into the new hibernate session, but I would avoid this approach altogether.
Instead try storing a key on the HttpSession that can be used to look up a User through hibernate for every incoming request. If you are worried about the performance consequences of visiting the database to retrieve something that can be stored in the HttpSession instead, fear not - you can always use a caching framework supported by hibernate to reduce the number of database visits. Another way to improve performance would be to use optimistic locking.
Although I have not looked at the hibernate sources, I think hibernate uses the "Identity Map" pattern. This is a Map that uses the entity's id as a key in the Map and the associated entity object as a value in the Map. Whenever an entity is retrieved from the hibernate session, hibernate will look at session's identity map to see if it is there. If it is there it will return the entity from the map. If it is not there it will retrieve the entity from the database and put it on the map, and then return the entity. This means that consecutive queries that access a given User with the same key (ie id, userId etc) for a given hibernate session will receive a reference to the same User object, and therefore each query will be able to "see" modifications made to the User object by the other query. For this reason it is absolutely imperative to create a new hibernate session for each incoming request, so that concurrent requests for a given User do not have to lock their respective threads on their common User object. Different hibernate sessions will each have their own identity map and therefore will not return references to the same User object.
By attempting to merge a User object from the HttpSession into your hibernate session you are basically trying to manipulate hibernate's IdentityMap directly, replacing whatever hibernate "thinks" ought to be there with something else, and understandably this can cause problems. As I said although it is possible to attach a detached object back into a hibernate session I would avoid it. Good luck with whatever approach you take.
I would highly recommend reading the following, in your case particularly the sections on long conversations and detached objects:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html
Depends on if the user changes during the session, or if you just want the id, name, etc. for a quick lookup. You can always merge() the user from the db to have it in the session again.
You don't need to merge the user everytime, because its a database hit which you don't always need. But with merge, you reattach the user to the current session.
Use session.merge(..)
(From Session
's docs):
The state of a transient or detached instance may also be made persistent as a new persistent instance by calling merge().
Just be sure to override hashCode()
and equals()
properly.
精彩评论