2016-06-27 14 views
0

Ich habe gerade Hibernate's optimistisches Locking letzte Woche gelernt und es in meine Anwendung eingeführt, die mit Spring JPA und MySQL DB geschrieben wurde.optimistische Sperrung fehlgeschlagen; verschachtelte Ausnahme ist org.hibernate.StaleObjectStateException, wenn ich einen Datensatz mit Spring Data's CrudRepository erhalte

Meine Entity wie folgt aussieht, wurde die Version Anmerkung gerade hinzugefügt,

@Entity  
public class Instance { 
    ... 

    @javax.persistence.Version 
    private Date updateTime; 

    ... 

    pubic Instance() { 
     this.updateTime = new Date(); 
    } 

} 

Und ich habe eine org.springframework.data.repository.CrudRepository für persistierende der Daten verwendet. Während ich verified Aktualisierung bestehende Rekord funktioniert gut, ist das Problem, es Ausnahme auslösen würde, wenn ein neues Objekt persistierenden

inst = new Inst(); 
instanceRepo.save(inst); 

Die geworfene Ausnahme

org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [Instance] with identifier [a5deddb9-d76c-433f-8b0d-e50cbf8f601e]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : 
    at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2541) 
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3285) 
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3183) 
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3525) 
    at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:159) 
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:465) 
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:351) 
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350) 
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56) 
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1258) 
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425) 
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101) 
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177) 
    at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77) 
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:131) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) 
    at com.sun.proxy.$Proxy139.save(Unknown Source) 

ist Dies ist einfach der erste Persistenz Anruf und ich glaube nicht, dass es mehrere Threads gibt, die versuchen, diesen Datensatz zu aktualisieren, also bin ich verwirrt, warum diese Ausnahme ausgelöst wird.

Auch habe ich versucht, in den zugrunde liegenden Code zu verfolgen, und hier ist einige Erkenntnisse hilfreich sein könnten,

  1. Wenn die zugrunde liegende org.springframework.data.jpa.repository.support.SimpleJpaRepository#save(S) Aufruf wie unten eingefügt, geht der Code in die Zusammenfassungslogik, obwohl diese ist ein neuer Datensatz,

    public <S extends T> S save(S entity) { if (entityInformation.isNew(entity)) { em.persist(entity); return entity; } else { return em.merge(entity); } }

  2. eine Ausnahme tritt auf, wenn es um die Transaktion zu verpflichten versucht und die DB zu spülen.

+0

ist nicht das, was sollte, falls Sie zufällig eine abgestandene bezwecken .. das ist, warum wir die optimistische Sperren benutzen? – Zulfi

Antwort

1

Die PPV spec sagte, dass
The following types are supported for version properties: int, Integer, short, Short, long, Long, java.sql.Timestamp.

Es Problem sein kann, wenn Sie java.util.Date Typ verwenden.

+0

Danke, ich habe das gesehen und die von @Zulfi vorgeschlagene Methode versucht, aber auch nicht funktioniert. – Derek

+0

Wie ich verstehe, wird das @Version-Feld von der JPA-Engine selbst aktualisiert werden. Daher sollten Sie in Ihrem Code keinen Wert für das @ Version-Feld festlegen und auch dessen Wert nicht initialisieren. Versuchen Sie, dies zu entfernen this.updateTime = new Date(); –

1

@Version Anmerkung kann auch für Datumsfelder verwendet werden, wenn Ihre JPA-Provider unterstützt, dass .Aber Sie würden das Datumsfeld mit @Temporal Annotation zur Karte zu, wie unten

@javax.persistence.Version 
@Temporal(TemporalType.TIMESTAMP) 
private Date updateTime; 

Für weitere Informationen wenden Sie sich bitte unter besuchen

Link

http://www.byteslounge.com/tutorials/jpa-entity-versioning-version-and-optimistic-locking

+0

Danke für die Antwort, ich fand diese Verwendung tatsächlich gestern und versuchte genau dasselbe, aber irgendwie hat es nicht wie erwartet funktioniert. Ich habe in den 'save'-Aufruf gecrackt, aber gefunden, als es versucht, den 'version'-Typ zu bestimmen, erhält er immer noch' Date' anstelle von 'TIMESTAMP' und derselbe Fehler taucht immer noch auf. Weißt du, warum? – Derek