Я написал сервис 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, я подумал, что я буду в безопасности от одновременных несоответствий, добавив синхронизированный блок выше. Я создал простой клиент для тестирования параллелизма, так как сервис предоставляется http invoker. Я запускал несколько клиентов одновременно, передавая в качестве аргумента один и тот же 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).
Я не знаю, что и думать, поскольку единственное, что я изменил, - это база данных. Буду признателен за любые советы по этому вопросу.
Я использую:
Грааль 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)
Заранее спасибо!