0
votes

-- Update: It turns out that we can't update any domain object at all. We created very simple domain/service/controller combination and still getting the StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.sra.cgms.test.TestDomain#1] Here is our domain class

class TestDomain {

    static mapping = {
         table name:'TEST_DOMAIN', schema:'cgms'
         id generator:'identity', column:'id', sqlType: 'int'
    }

    String someVal

    static constraints = {

        someVal(nullable: true)
    }
}

Here is our service class:

class TestService {

    public void updateDomain(int domainId) {
        TestDomain testDomain = TestDomain.get(1)
        testDomain.someVal = "updated Val"
        testDomain.save(flush: true, failOnError: true)
    }
}

And here is our controller:

class TestController {

    def testService


    def updateData() {

        testService.updateDomain(1);

        render "Data updated"
    }
}

Also, when we try calling testService.updateDomain(1) from Grails console, it worked without issue.

-- End Update

Hoping someone in the Groovy/Grails projects encountered this (strange) behavior before:

We are trying to upgrade our current Grails 1.3.7 version to Grails 2.4.5 and getting StaleObjectStateException on a few places (when submitting a form)

The messages typically looks like:

Object of class [com.sra.cgms.workflow.WorkflowTaskHistory] with identifier [212430]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.package.workflow.WorkflowTaskHistory#212430]

Our environment configuration is:

  • Groovy 2.3, Grails 2.4.5, Hibernate 4.3.8.1 (also tried 3.6.10.18), SQL Server 2008, JTDS JDBC Driver 1.2.5 (also tried 1.3.1)

We looked around the web and typically people are getting this exception when in a multi users environment. But this happens for us when testing locally as a single user. We tried quite a few suggestions:

  • Turning off Hibernate optimistic locking (disable version in GORM domain entity)
  • Lock object before saving to db..

None of the above helps. Here is a snippet in DataSource.groovy:

    hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = false
    //cache.region.factory_class = 'org.hibernate.cache.SingletonEhCacheRegionFactory' // Hibernate 3
 cache.region.factory_class = 'org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory' // Hibernate 4
    singleSession = true // configure OSIV singleSession mode
    flush.mode = 'manual' // OSIV session flush mode outside of transactional context
}

// environment specific settings
environments {
 local {
  dataSource {
   dbCreate = "update" // one of 'create', 'create-drop','update'
   url = "jdbc:jtds:sqlserver://localhost/test_local"
   username="dbuser"
   password="secret"
   driverClassName="net.sourceforge.jtds.jdbc.Driver"
   logSql = true
   properties {
           maxActive = 100
           maxIdle = 25
           minIdle = 5
           initialSize = 5
           testOnBorrow = true
           validationInterval = 30*1000 //30 seconds
           validationQuery = "SELECT 1"
     //defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED
   }
  }
 }
}
1
Can you post the code that's saving the WorkflowTaskHistory instance?Emmanuel Rosa
This usually happens because of any modifications in the existing object and detachment from current session. try obj.refresh() or obj.merge() before saving.Vinay Prajapati
Thanks Emmanuel and Vinay for commenting. I've just updated the question to include the code that saves WorkflowTaskHistory instance. I will try your suggestion Vinay. A tricky part is that this is a big process with quite a few database operations. Some are explicit save to WorkflowTaskHistory (like code posted above). Some are triggered by saving related entities.TSra
We discovered that we can't retrieve an instance of a domain class, update some value, then save. So not just the scenario we originally described. I've updated the question to describe the new scenario. Any pointer/suggestion is appreciatedTSra
are you sure, you are not messing up with object.version?injecteer

1 Answers

0
votes

As it turns out, the source of this StaleObjectStateException issue doesn't have anything to do with the config or code.

We have in our BootStrap.groovy code to run several SQL scripts to initialize our database (MS SQL Server) at application start up. A few of those SQL scripts contain the following

SET NOCOUNT ON;

We believe that line causes SQL Server to always returns 0 for update statements (maybe other type of SQL statements as well). When Hibernate executes the update statement and examines the return value, it always find 0. Hibernate compares that with the expected value (which is 1 for domain.save() call). The expected value and the return value don't match so Hibernate think the data is stale, therefore it throws the StaleObjectStateException. Note that Hibernate does this checking whether you turn on version or not.

Hope this info help those out there with similar situation