我用以下代码编写了一个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)
提前致谢!
答案 0 :(得分:1)
这很奇怪,请尝试禁用交易。
答案 1 :(得分:0)
这确实是一种奇怪的行为,但您可以尝试通过使用" select ... for upgrade",通过hibernate锁定方法来解决此问题。
这样的事情:
def c = SerialGenerator.createCriteria()
serialgenerator = c.get {
eg "itemReferece", itemReference
lock true
}