mysql - 乐观锁失败;使用 Spring Data 的 CrudRepository 保存记录时,嵌套异常为 org.hibernate.StaleObjectStateException

标签 mysql hibernate spring-data optimistic-locking

我上周刚刚学习了 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 规范是这么说的
版本属性支持以下类型:int、Integer、short、Short、long、Long、java.sql.Timestamp。

使用java.util.Date类型时可能会出现问题。

关于mysql - 乐观锁失败;使用 Spring Data 的 CrudRepository 保存记录时,嵌套异常为 org.hibernate.StaleObjectStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38064577/

相关文章:

java - Spring中如何在一个事务方法中管理多个事务?

mysql - 在mysql的一列中创建多个值

mysql - 如何跳过 sqlSave() 命令中的主键?

mysql - 是否有任何Linux命令来查找mysql数据库的内存消耗?

mysql - Spring、Hibernate、MySQL - 事务如何工作 - 结论/问题**

java - 如何使 Autowiring 注释工作?

php - 从跨越多天的数据库中获取事件

java - session.load()方法如何在不访问数据库的情况下提取数据?

spring - 无法使用 spring jpa 获取更新的实体并且唯一约束不会停止更新

spring-boot - 如何从应用程序启动中删除 Spring Data CustomConversions 警告?