-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 
Author Message
 Post subject: StaleObjectState and NonUniqueObject exceptions
PostPosted: Fri Apr 10, 2009 2:05 pm 
Newbie

Joined: Fri Apr 10, 2009 11:45 am
Posts: 4
Location: Pewaukee, WI USA
Hibernate version: 3.2.5
Mapping documents: will post if necessary
Code between sessionFactory.openSession() and session.close(): not relevant (using spring HibernateTemplate methods)
Full stack trace of any exception that occurs: will post if necessary
Name and version of the database you are using: Oracle 10
The generated SQL (show_sql=true): will post if necessary
Debug level Hibernate log excerpt: not available

I know you normally want all the above info up front, but I will be precise asking my question, and if I need to provide further info I will. I have read many articles, posts, I've read the relevant portions of the manual, and I've debugged and reduced this problem down to a very direct set of questions.

Dozens of exceptions thrown on a weekly basis... all StaleObjectState and NonUniqueObject. We're using Spring's org.springframework.orm.hibernate3.HibernateTemplate, calling its methods for session operations. The JavaDoc for that class states that it
Quote:
"provides Hibernate Session handling such that neither the HibernateCallback implementation nor the calling code needs to explicitly care about retrieving/closing Hibernate Sessions, or handling Session lifecycle exceptions."

The problem, I believe, is that the app is a Java desktop app served via JNLP. So each user has their own session/cache, etc., which essentially (I think I understand after reading the manual) robs Hibernate of one of its greatest strengths. Optimistic locking is in use via <version> tags. All fields in data objects are non-primitives. All mappings supply unsaved-value specifics where appropriate. Hibernate appears to be doing exactly what it's designed to do with respect to optimistic locking, and like the manual says, these errors are designed to represent unrecoverable situations.

For the time being, however, I'm supposed to fix this or suggest a redesign, but I'm new to Hibernate so I'm trying to learn a little more from the forum. The unique nature of this app makes it so that most of the posts I read provide only tangential information. They're experiencing these conditions for normal reasons under normal Hibernate scenarios (batch updates, constraint violations, etc.) I'm experiencing them because this multi-user, nobody's-session-knows-about-each-other scenario may be a slight misuse of Hibernate, and may (theory) mean I'll have to do more direct session manipulation than would normally be suggested.

So here's what's happening. We're calling (throughout the software):
Code:
HibernateTemplate.find(String, Object[])
HibernateTemplate.saveOrUpdate(Object)
HibernateTemplate.merge(Object)

(merge is tried as a recovery attempt from exceptions thrown by saveOrUpdate... yes I know that is explicitly discouraged... I'm new on this app and I'm just trying to understand)

The find(String, Object[]) call often produces:
Code:
org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException:
Object of class [foo.bar.CategoryData] with identifier [881791]:
optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException:
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [foo.bar.CategoryData#881791]
with log output (from Hibernate) that says:
Code:
ERROR (performExecutions:301) Could not synchronize database state with session


The saveOrUpdate(Object) call sometimes produces the same exception (StaleObj) and the same log output, and other times it produces:
Code:
org.hibernate.NonUniqueObjectException:
a different object with the same identifier value was already associated with the session: [foo.bar.CategoryData#851289]


In that case, the code immediately tries to recover with a merge(Object), which produces again (you guessed it):
Code:
org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException:
Object of class [foo.bar.CategoryData] with identifier [881791]:
optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException:
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [foo.bar.CategoryData#881791]
with log output (from Hibernate) that says:
Code:
ERROR (performExecutions:301) Could not synchronize database state with session


My questions:
1) What exactly does the phrase "Could not synchronize..." mean in terms of how it determines that? I can see it's coming from AbstractFlushingEventListener, which means the operations we're performing are causing a flush. Is it simply that in trying to persist its state, the StaleObjectStateException is marking an objection to a version issue, and NonUniqueObjectException is saying the code is violating session-scoped identity? Is that always exclusively a problem with equals() and hashcode() implementations, or are there other things we could be doing wrong?

2) What are my options under the StaleObjectState circumstances? I've read tons of posts about the "evict" method? Does that work? If I have version 1 in the session, the DB has version 4, and a saveOrUpdate fails, can I simply evict that Stale instance and then call saveOrUpdate again?

3) If I did evict the stale instance, how do I avoid overwriting what some other user (another instance of the app, Hibernate, etc) wrote to the DB?

4) What are my options under the NonUniqueObjectException scenarios? I don't understand why saveOrUpdate would care if there's a different object with the same identifier? Isn't that the session's copy of the object I want to update, or is it actually saying it's a DIFFERENT object that identifies the same as the one I have a reference to?

I'll stop there. These are the most basic questions I have.
Any help would be greatly appreciated.

_________________
Pete Ihlenfeldt


Top
 Profile  
 
 Post subject: Anything?
PostPosted: Mon Apr 13, 2009 12:37 pm 
Newbie

Joined: Fri Apr 10, 2009 11:45 am
Posts: 4
Location: Pewaukee, WI USA
Anyone have anything at all for me about:
- how a Hibernate Session reaches a state where there are Stale objects in it,
- the scenario I described (multiple desktop apps all using their own cache / how to handle reconciling that cache with the database when the user wants to save,
- what "Could not synchronize database state with session" means in the context of a flush,
- perhaps an alternative way I should be approaching this problem?

Anything?

_________________
Pete Ihlenfeldt


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 13, 2009 11:33 pm 
Newbie

Joined: Mon Apr 06, 2009 10:48 pm
Posts: 4
Location: Wellington, New Zealand
From the sound of things, it seems like your application is possibly keeping Hibernate sessions open for longer than might be advisable. In general, a Session object is intended to be fairly short-lived, in order to avoid such problems of stale objects. It is a fairly common pattern in web applications to use a session per HTTP request, such that that the session lifetime is less than one second. Longer session lifetimes are certainly possible--I'm working with a session-per-conversation model in which the session can live for some minutes--but in such cases you need to be particularly aware of the possibility of stale objects, and have a strategy for handling it.

If you are attempting to use a single Hibernate session for the life of a client, things could get hairy.

To try to answer your specific questions:

Quote:
- how a Hibernate Session reaches a state where there are Stale objects in it


Simply enough, if the database state of one of those objects changes since it was loaded into the Session in question. (The change would have to happen via another Session of course.)

Quote:
- the scenario I described (multiple desktop apps all using their own cache / how to handle reconciling that cache with the database when the user wants to save


Having a Session per user/client is not an unusual pattern. As I mentioned above, shortening the Session lifespan is likely to reduce the problems you run into. You can still run into stale state problems, but they should be fewer. It might be a viable option to simply abort the current operation and make the user try again, or create an explicit change-merging process to handle it, if not.

Quote:
- what "Could not synchronize database state with session" means in the context of a flush


It looks like that message is printed if an exception is thrown during the session flush process. If auto flush mode is used, before running 'find', the session is flushed. Stale object state was encountered during that flush process.


Hope that's of some help; I'm rather a newbie myself. I recommend getting a copy of 'Java Persistence with Hibernate'; it's clarified a lot of things for me.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 14, 2009 2:40 pm 
Newbie

Joined: Fri Apr 10, 2009 11:45 am
Posts: 4
Location: Pewaukee, WI USA
First of all, thank you for the response. I appreciate the honest effort to put some thought into this on my behalf.

I think one of the things that I need to understand is how the HibernateTemplate deals with the session. When I call isAlwaysNewSession(), it returns false, which makes me wonder what turning that on would do. The JavaDoc for that setter almost sounds like what I would want. Not sure though. I know I don't want to use the same session throughout. I can see how that would be a nightmare. Like I said in the original post, the docs for HibernateTemplate make it sound like you literally need not worry about session management when using the Template. I'm assuming it uses session-per-conversation, but I don't know. Perhaps it's just the level of activity and the nature of / prevalence of massive updates in this software that is making even a Template-managed session highly susceptible to stale objects.

I agree completely that you need to be aware of the possibility of stale objects and have a strategy for it. I'm just not certain what that strategy should be at this point. I think one of the issues in the software I'm working on is that any one action by a user can mean literally hundreds of insertions/deletions/updates to other records. You "save" a product (which belongs to categories and has other associations)... all of those one-off pieces of information get saved. So it's possible that one of the Stale objects encountered during the flush is an object I indirectly need to update.

One particular unknown for me: I have (basically) the following setup...
Code:
<bean id="fooDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="${foo.driverClassName}" />
  <property name="url" value="${foo.url}" />
  <property name="username" value="${foo.username}" />
  <property name="password" value="${foo.password}" />
  <property name="initialSize" value="5" />
  <property name="maxActive" value="10" />
  <property name="maxIdle" value="1" />
  <property name="validationQuery" value="select top 1 * from FooTable" />
</bean>

<bean id="oracleSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="dataSource" ref="fooDataSource" />
  <property name="mappingResources">
    <list>
      <value>Foo1.hbm.xml</value>
      <value>Foo2.hbm.xml</value>
      <value>Foo3.hbm.xml</value>
    </list>
  </property>
  <property name="hibernateProperties">
    <props>
      <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9iDialect</prop>
      <prop key="hibernate.show_sql">false</prop>
      <prop key="hibernate.lazy">false</prop>
      <prop key="hibernate.use_outer_join">true</prop>
      <prop key="hibernate.cache.use_second_level_cache">false</prop>
    </props>
  </property>
</bean>

<bean id="fooDao" class="com.company.fooDaoImpl">
    <property name="sessionFactory" ref="oracleSessionFactory"/>
</bean>

...but there are many of these datasources, many session factories, many daos. All the Dao's extend HibernateDaoSupport, which gives them access to the getHibernateTemplate method, through which all their calls are made. how would one describe the effect a setup like that has on session management (when taken in conjunction with the application deployment scenario I've described)? Is this even the right way to set it up?

Other "unknowns":
- what would happen if I just evicted anything that was stale? I've seen comments on that elsewhere, but it sounds more like a hack than an advisable tactic.
- merge(Object) is supposed to remedy this situation. Why doesn't it work? Is it actually that the StaleObjectStateException I'm getting is on another object Hibernate is trying to flush and not the ones I'm trying to save? Quite confusing to me.

My understanding is that, when using Hibernate, you should presume the same level of control over persistence to the actual DB as we presume control over garbage collection in Java. You are supposed to interact with the session as though it is the persistent state. But if my persistent state is inaccurate, and I can't evict, can't merge, can't flush... what am I gaining?

_________________
Pete Ihlenfeldt


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 14, 2009 2:46 pm 
Newbie

Joined: Fri Apr 10, 2009 11:45 am
Posts: 4
Location: Pewaukee, WI USA
By the way... I'm buying a copy of that book on the way home. Thanks for the advice.

_________________
Pete Ihlenfeldt


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 15, 2009 12:47 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
http://in.relation.to/Bloggers/UsingAbstractionFrameworksToMaintainControlWrongBet

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject: Re: StaleObjectState and NonUniqueObject exceptions
PostPosted: Thu Jul 01, 2010 10:06 am 
Newbie

Joined: Thu Jul 01, 2010 9:21 am
Posts: 2
I hope that you have solved the issue. I am also having a similar problem and its in a production system which causing delay in the production and by going through the chain of anger/heat transfer, in the end I am getting grilled.

I am getting this exception in a controller of a web application based on spring framework using hibernate.

In the controller's method, handleRequestInternal, there are calls made to the database mainly for 'read', unless its a submit action.
I have been using, Spring's Session but completely changed dao layer to use getHibernateTemplate() but the problem still remains.

basically, the second call to the database throws this exception. That is:

1) getEquipmentsByNumber(number) { firstly an equipment is fetched from the DB based on the 'number', which has a list of properties and each property has a list of values. I loop through those values (primitive objects Strings) to read in to variables)

2) getMaterialById(id) {fetches materials based on id}

I do understand that the second call, most probably, is making the session to "flush", but I am only 'reading' objects, then why does the second call throws the stale object state exception on the Equipment property if there is nothing changed?

I cannot clear the cache after the call since it causes LazyExceptions on objects that I pass to the view.

What can I do to resolve this, any idea thought would be appreciated.

UPDATE: What I just tested is that in the function getEquipmentsByNumber after reading the variables from list of properties, I do this: getHibernateTemplate().flush(); and now the exception is on this line rather then the call to fetch material (that is getMaterialById(id)).

UPDATE: Before explicitly calling flush, I am removing the object from session cache so that no stale object remains in the cache. getHibernateTemplate().evict(equipment); getHibernateTemplate().flush();

OK, so now the problem has moved to the next fetch from DB after I did this. I suppose I have to label the methods as synchronized and evict the Objects as soon as I am finished reading their contents! it doesn't sound very good.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.