有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Spring Hibernate StaleObjectStateException由于新的HashSet?

我的代码在很长一段时间内运行良好,但经过几次重构后,我发现我突然无法保存Group对象

我犯了一个可怕的错误。在谷歌搜索之后,我当然找到了this StackOverflow question,但这对我毫无帮助,因为我没有同时做任何事情

在经历了重构之后,我发现唯一的区别就是这个变化

在此之前:

    final Collection<Sample> allByBarcode = sampleService.byBarcode(groupRequest.getSamples(), currentUser);

    if (!allByBarcode.isEmpty()) {
        Group group = new Group();

        group.setName(groupRequest.getName());
        group.setSamples(allByBarcode);
        group.setType(groupRequest.getType());
        group.setOwner(currentUser);

        group = repository.save(group);

        return Optional.ofNullable(group);
    }

重构后(不记得确切原因),它变成:

    final Collection<Sample> allByBarcode = sampleService.byBarcode(groupRequest.getSamples(), currentUser);

    if (!allByBarcode.isEmpty()) {
        Group group = new Group();

        group.setName(groupRequest.getName());
        group.setSamples(new HashSet<>(allByBarcode));
        group.setType(groupRequest.getType());
        group.setOwner(currentUser);

        group = repository.save(group);

        return Optional.ofNullable(group);
    }

在把它改回原来的版本后,它每次都突然重新开始工作,没有任何错误

有人能解释一下这个错误的原因吗?因为这是代码中唯一让它再次工作的区别

更新1:

我尝试了另一种变体:

Group group = new Group();

group.setName(groupRequest.getName());
group.setSamples(new ArrayList<>(allByBarcode));
group.setType(groupRequest.getType());
group.setOwner(currentUser);

group = repository.save(group);

请注意ArrayList而不是HashSet–出于某种原因,此代码有效

我也试过LinkedList,它也能工作

有什么想法吗

更新2:

堆栈跟踪如下所示: 我把它剪下来,去掉了很多与Spring和Tomcat相关的痕迹

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [uk.ac.sanger.mig.aker.domain.Group] with identifier [93]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [uk.ac.sanger.mig.aker.domain.Group#93]] with root cause

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [uk.ac.sanger.mig.aker.domain.Group#93]
        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:1222)
        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:757)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:521)
        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.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
        at com.sun.proxy.$Proxy116.createGroup(Unknown Source)
        at uk.ac.sanger.mig.aker.controllers.GroupController.store(GroupController.java:107)

共 (3) 个答案

  1. # 1 楼答案

    在新代码中,您正在创建一个新的HashSet,它将包含allByBarcode集合中的所有Sample元素

    我认为这里提出的问题是因为这些元素没有被会话持久化,因为它们是添加到new HashSet()实例的新对象,并且它们没有被会话真正保存,它解释了Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect){}但是allByBarcode元素是从您的服务中获取的,因此它们是持久化的,并且被会话识别为

    我看不出有什么必要设置一个新的HashSet实例,在这个实例中,会话应该保存(持久化)元素(因为您试图使用现有标识符保存元素,所以会抛出一个Exception),而设置已经保存的元素更高效、更安全,因此更好地使用:

       group.setSamples(allByBarcode);
    
  2. # 2 楼答案

    由于您已经将samples对象初始化为HashSet,您可以尝试这样做而不是再次初始化它

    group.getSamples().addAll(allByBarcode);
    
  3. # 3 楼答案

    我认为问题在于,您的集合中存在一些重复的对象allByBarcode,当您将集合包装在不允许重复的哈希集中时,这些对象将消失。之后发生的情况是:存储库多次尝试保存同一对象