2010-11-25 4 views
2

J'ai écrit un service de Grails avec le code suivant:org.hibernate.StaleObjectStateException lors de l'utilisation Grails avec PostgreSQL

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... 
} 

Être un Grails Le service est un singleton par défaut, je pensais que je serais sûr de concurrent incohérence en ajoutant le bloc synchronisé ci-dessus. J'ai créé un client simple pour tester la concurrence, car le service est exposé par http invoker. J'ai couru plusieurs clients en même temps, en passant en argument le même itemReference, et je n'ai eu aucun problème. Cependant, lorsque j'ai changé la base de données de MySQL à PostgreSQL 8.4, je ne pouvais plus gérer l'accès simultané. Lorsque vous exécutez un seul client, tout va bien. Cependant, si j'ajouter un client demandant le même ItemReference, je reçois instantanément une 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] 

Note: EPCGeneratorService.groovy: 63 fait référence à serialGenerator.save (flush: true).

Je ne sais pas quoi penser, comme la seule chose que j'ai changé était la base de données. J'apprécierais tout conseil à ce sujet.

J'utilise:
Grails
Postgres 1.3.3 8.4 (driver postgresql-8.4-702.jdbc4)
JBoss 6.0.0-M4

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

Merci d'avance!

Répondre

1

C'est bizarre, essayez de désactiver la transaction.

0

Ceci est en effet un comportement étrange, mais vous pouvez essayer de contourner le problème en utilisant un "select ... pour la mise à niveau", via la méthode de verrouillage hibernate.

Quelque chose comme ceci:

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