Michael
Michael

Reputation: 33297

Grails: events.PatchedDefaultFlushEventListener - Could not synchronize database state with session org.hibernate.StaleObjectStateException

I got the following error in my app.

ERROR events.PatchedDefaultFlushEventListener  - Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [buddyis.User#848df2e62fcf93e1b3]
    at buddyis.SessionResource$_login_closure1.doCall(SessionResource.groovy:104)
    at org.grails.datastore.gorm.GormStaticApi.withTransaction(GormStaticApi.groovy:814)
    at org.grails.datastore.gorm.GormStaticApi.withTransaction(GormStaticApi.groovy:714)
    at buddyis.SessionResource.login(SessionResource.groovy:41)
    at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
    at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
    at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
    at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)
    at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
    at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
    at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
    at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1511)
    at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1442)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1391)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1381)
    at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:538)
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:716)
    at org.grails.jaxrs.web.JaxrsContext$JaxrsServiceImpl.process(JaxrsContext.java:193)
    at org.grails.jaxrs.JaxrsController.handle(JaxrsController.groovy:45)
    at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:198)
    at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
    at org.grails.jaxrs.web.JaxrsFilter.doFilterInternal(JaxrsFilter.java:46)
    at com.github.greengerong.PreRenderSEOFilter.doFilter(PreRenderSEOFilter.java:65)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

What does this error mean and how can I prevent it?

Upvotes: 1

Views: 2717

Answers (1)

Dónal
Dónal

Reputation: 187499

This exception is caused by the following

  • Ann reads a row
  • Bob reads the the same row
  • Bob updates the row
  • Ann attempts to update the row, but the attempt fails because Hibernate notices that it has been updated since Ann read it

It's very difficult to advise you what to do about this, because you haven't provided any contextual information, e.g. who or what is reading/updating the row. Here is some general advice:

If you don't care about this scenario, and would like Ann to be able to update the row even though it has been updated (by Bob) since she read it, just disable optimistic locking by adding the following to the relevant domain class

static mapping = {
    version false
}

Alternatively, you can check in your controller whether the row has been updated since Ann read it, and if so, show her the updated row, so she can re-apply her updates to the latest data. The check in the controller can be performed by storing the version no. (that Ann read) in a hidden form field. When Ann's update is submitted (with the hidden version no.), load the object from the database and check that the submitted version no. equals the version no. of the object loaded from the database. If the numbers are different, display the latest version of the row along with a message informing her about what has happened.

Of course, the suggestion above is only applicable if the row is being updated by users submitting forms. But as I said, your question doesn't include any context, and my crystal ball is low on battery.

Upvotes: 3

Related Questions