2016-06-27 40 views
0

先週、Hibernateのオプティミスティックロックを学び、Spring JPAとMySQL DBで書かれた自分のアプリケーションに導入しました。私のエンティティは次のようになりオプティミスティック・ロックに失敗しました。 SpringデータのCrudRepositoryでレコードを永続化するときのorg.hibernate.StaleObjectStateException

Version注釈は単に、追加

@Entity  
public class Instance { 
    ... 

    @javax.persistence.Version 
    private Date updateTime; 

    ... 

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

} 

そして私は、データを永続化するために使用さorg.springframework.data.repository.CrudRepositoryを持っていました。私は既存のレコードを更新すると、正常に動作検証しながら、問題は新しいオブジェクトを永続化するときに例外をスローされますされ、スロー

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

例外が

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) 

これは単に最初の永続化のコールと私でありますこのレコードを更新しようとするスレッドが複数あるとは思わないので、なぜこの例外がスローされるのか混乱します。

はまた、私は基本的なコードにトレースすることを試み、そしてここでいくつかの所見が役に立つかもしれませんで、以下の貼り付けなど基礎となるorg.springframework.data.jpa.repository.support.SimpleJpaRepository#save(S)を呼び出すとき

  1. 、コードも、このかかわらず、マージ・ロジックに移動します新しいレコードが、ある

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

  2. それはトランザクションをコミットし、DBをフラッシュしようとしたときに例外が発生します。

+0

たちは楽観的ロックを使用する理由です..あなたは、古いオブジェクトを持っている場合に起こることになっているものことではないでしょうか? – Zulfi

答えて

1

JPAの仕様では、java.util.Date型を使用したときに
The following types are supported for version properties: int, Integer, short, Short, long, Long, java.sql.Timestamp.

は問題がある可能性があると述べました。あなたのJPAプロバイダは、あなたがより多くの詳細については

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

以下のようにあまりにも@Temporal注釈付き日付フィールドをマッピングしなければならない.But下記をご覧くださいことをサポートしている場合

+0

ありがとう、私はこれを見て、@ Zulfiが提案した方法を試しましたが、どちらもうまくいきませんでした。 – Derek

+0

私が理解しているように、@VersionフィールドはJPAエンジン自体によって更新されます。あなたのコードでは、@ Versionフィールドに値を設定するのではなく、その値も初期化しないでください。 this.updateTime = new Date();を削除してください。 –

1

@Version注釈はまた、日付フィールドのために使用することができますリンク

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

+0

答えてくれてありがとう、私は実際にこの昨日この使用法を見つけて、まったく同じことを試しましたが、どういうわけかそれは期待どおりにうまくいかなかったのです。私は 'save'呼び出しをトレースしましたが、' version'型を判断しようとしたときに 'TIMESTAMP'ではなく' Date'を取得していますが、同じエラーがまだ表示されています。なぜなのかご存知ですか? – Derek

関連する問題