Ok, here's a new twist on a frequently asked question:
Given the following classes:
UserSession - stored in a table called user_sessions, represents an http session.
SessionAction - Every click created by the user generates one of these. A SessionAction has a method setSession(UserSession us); to allow association of actions to sessions.
User - information about a user, this class
does have a collection of Role objects associated with it.
Neither of the first two classes have collections.
All 3 classes are persisted to the database via Hibernate.
when I log a SessionAction to the database, I do the following:
Code:
//simplified code; retrieve user object:
User user = getUser(username, password);
UserSession us = (UserSession)httpRequest.getSession().getAttribute("userSession");
us.setUser(user);
//now the user is associated with their session
Then, when they view a page, that action is logged:
Code:
UserSession us = (UserSession)httpRequest.getSession().getAttribute("userSession");
SessionAction action = new SessionAction(pageURL);
//associate the action with its session:
action.setSession(us);
Then, in a DAO proxied by a Stateless Session Bean (try/catch blocks removed for clarity), the following method is called:
Code:
public void log(SessionAction action) {
Session hibernateSession = factory.openSession();
hibernateSession.save(action);
hibernateSession.flush();
hibernateSession.close();
}
This method
sometimes throws the "Illegal attempt to associate a collection with two open sessions" exception when hibernateSession.save() is called and works just fine other times.
For example, after logging in, the user is directed to a frameset with 4 different jsp pages. Each page view causes a call to the above log method, since each page view is logged. When the 4th page loads, the exception is thrown. The whole frameset loading happens fairly quickly, and I'm wondering if errors occur due to transactional issues with JBoss/Tomcat. However,
every method in my DAO gets a session from the Hibernate factory and closes it before the method returns, so no sessions are being shared or accidentally left open. I even specified an EJB transactional attribute of "RequiresNew" for every method on that SLSB to ensure each call to "log" would operate within a new transaction.
The code that executes per page load is
exactly the same. There is one HTTP request processor that logs each http request and calls the SLSB's log(SessionAction) method.
Note that the UserSession object does reside in memory between hibernate session openings/closings. I don't know that this would be a problem. However, it doesn't have any collections that might cause the above exception message.
However, the UserSession object
does have a reference to a User object, which in turn does have a roles collection.
Is this (indirect) collection the one that is giving me problems? If so, how come it doesn't fail every time the log method is called?
Just to see if it would work, in the above log method, I first query for the UserSession in the database (instead of using the one already in memory), and use
that instance when calling the SessionAction.setSession(UserSession us); method. This approach executes fine every time.
Unfortunately, this is not an acceptable option for me, because it requires a query
and an insert to the db for
every action that is logged. There is an awful lot of logging going on and this approach essentially doubles my db performance hit.
Gavin, Max, Christian, or anyone else...can you please explain to me why this would be happening (working some times and not others)? Is this due to transactional/session issues with JBoss/Tomcat? (I am using an older version...jboss-3.0.4_tomcat-4.1.12). Any ideas at all?
Thanks very much,
p
P.S. I'm using Hibernate 2.1 beta 2