与PostgreSQL一起使用Grails时的org.hibernate.StaleObjectStateException

时间:2010-11-25 13:59:06

标签: mysql hibernate spring postgresql grails

我用以下代码编写了一个grails服务:

EPCGenerationMetadata requestEPCs(String indicatorDigit, FilterValue filterValue,     
    PartitionValue partitionValue, String companyPrefix, String itemReference, 
    Long quantity) throws IllegalArgumentException, IllegalStateException {  

    //... code
    //problematic snippet bellow
    def serialGenerator
    synchronized(this) {
        log.debug "Generating epcs..."
        serialGenerator = SerialGenerator.findByItemReference(itemReference)
        if(!serialGenerator) {
            serialGenerator = new SerialGenerator(itemReference: itemReference, serialNumber: 0l)
        }
        startingPoint = serialGenerator.serialNumber + 1
        serialGenerator.serialNumber += quantity
        serialGenerator.save(flush: true)
    }
    //code continues...
}

默认情况下,作为一个单独服务的grails服务,我认为通过添加上面的synchronized块,我可以避免并发不一致。我已经创建了一个用于测试并发性的简单客户端,因为http调用者公开了该服务。我同时运行多个客户端,作为参数传递相同的itemReference,并且完全没有问题。

然而,当我将数据库从MySQL更改为PostgreSQL 8.4时,我再也无法处理并发访问。当运行单个客户端时,一切都很好。但是,如果我再添加一个客户端请求相同的itemReference,我会立即得到一个StaleObjectStateException:

Exception in thread "main" org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Object of class [br.com.app.epcserver.SerialGenerator] with identifier [10]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [br.com.app.epcserver.SerialGenerator#10]  
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:672)  
    at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)  
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:411)  
    at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)  
    at org.springframework.orm.hibernate3.HibernateTemplate.flush(HibernateTemplate.java:881)  
    at org.codehaus.groovy.grails.orm.hibernate.metaclass.SavePersistentMethod$1.doInHibernate(SavePersistentMethod.java:58)  
    (...)  
    at br.com.app.EPCGeneratorService.requestEPCs(EPCGeneratorService.groovy:63)  
    at br.com.app.epcclient.IEPCGenerator$requestEPCs.callCurrent(Unknown Source)  
    at br.com.app.epcserver.EPCGeneratorService.requestEPCs(EPCGeneratorService.groovy:29)  
    at br.com.app.epcserver.EPCGeneratorService$$FastClassByCGLIB$$15a2adc2.invoke()  
        (...)  
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [br.com.app.epcserver.SerialGenerator#10]

注意:EPCGeneratorService.groovy:63引用serialGenerator.save(flush:true)。

我不知道该怎么想,因为我唯一改变的是数据库。我对这件事的任何建议表示感谢。

我正在使用:
Grails 1.3.3
Postgres 8.4(postgresql-8.4-702.jdbc4驱动程序)
JBoss 6.0.0-M4

的MySQL:
mysqld Ver 5.1.41(mysql-connector-java-5.1.13-bin driver)

提前致谢!

2 个答案:

答案 0 :(得分:1)

这很奇怪,请尝试禁用交易。

答案 1 :(得分:0)

这确实是一种奇怪的行为,但您可以尝试通过使用" select ... for upgrade",通过hibernate锁定方法来解决此问题。

这样的事情:

def c = SerialGenerator.createCriteria()
serialgenerator = c.get {
  eg "itemReferece", itemReference
  lock true
}