簡體   English   中英

樂觀鎖定失敗; 使用Spring Data的CrudRepository保留記錄時,嵌套異常是org.hibernate.StaleObjectStateException

[英]optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException when persisting a record with Spring Data's CrudRepository

上周,我剛剛了解了Hibernate的樂觀鎖定,並將其介紹給了用Spring JPA和MySQL DB編寫的應用程序。

我的實體看起來像這樣,剛剛添加了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)

這只是第一個持久性調用,我不認為有多個線程試圖更新此記錄,因此我很困惑為什么拋出此異常。

我也嘗試追蹤基礎代碼,這是一些發現可能會有所幫助,

  1. 當按如下所示調用底層的org.springframework.data.jpa.repository.support.SimpleJpaRepository#save(S) ,即使這是一條新記錄,代碼也會進入合並邏輯,

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

  2. 當它嘗試提交事務並刷新數據庫時,會發生異常。

JPA規范說
The following types are supported for version properties: int, Integer, short, Short, long, Long, java.sql.Timestamp.

使用java.util.Date類型時可能會出現問題。

如果您的JPA提供者支持,@Version注釋也可以用於日期字段,但是您也必須將日期字段與@Temporal注釋映射如下

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

有關更多詳細信息,請訪問下面的鏈接

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM