Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 防止发生hibernate StaleObjectStateException_Spring_Hibernate_Jpa_Spring Data Jpa - Fatal编程技术网

Spring 防止发生hibernate StaleObjectStateException

Spring 防止发生hibernate StaleObjectStateException,spring,hibernate,jpa,spring-data-jpa,Spring,Hibernate,Jpa,Spring Data Jpa,我对Spring控制器方法有问题。它实际上在同一个实体上执行两次更新,从而导致StaleObjectStateException 问题是,当我检索成员实例时,我认为它会以某种方式导致广告实例的更新(请参见//更新一个),而当我更新广告实例时(请参见//更新两个),它会抛出一个StaleObjectStateException 我的问题是如何防止这种异常在我的案例中发生(记住我使用的是SpringDataJPA) 以下是成员实体类: @Entity public class Member { ..

我对Spring控制器方法有问题。它实际上在同一个实体上执行两次更新,从而导致StaleObjectStateException

问题是,当我检索成员实例时,我认为它会以某种方式导致广告实例的更新(请参见
//更新一个
),而当我更新广告实例时(请参见
//更新两个
),它会抛出一个StaleObjectStateException

我的问题是如何防止这种异常在我的案例中发生(记住我使用的是SpringDataJPA)

以下是
成员
实体类:

@Entity
public class Member {
...
@OneToMany(fetch = FetchType.LAZY, mappedBy = "member")
private List<Advertisement> advertisements;
...
@NotNull
@ManyToOne(fetch = FetchType.LAZY)
private Member member;
以下是控制器方法:

@RequestMapping(value = "/family/advertisement/edit", method = RequestMethod.POST, produces = "text/html")
    public String editFamilyAdvertisement(@ModelAttribute @Validated(value = Validation.AdvertisementCreation.class) FamilyAdvertisementInfo familyAdvertisementInfo,           BindingResult bindingResult, Model model) {
        Member member = memberService.retrieveCurrentMember();//UPDATE ONE
        if (!advertisementService.advertisementBelongsToMember(familyAdvertisementInfo.getFamilyAdvertisement(), member)) {
            throw new IllegalStateException("advertisement does not belong to member");
        }
        if (bindingResult.hasErrors()) {
            populateModel(model, familyAdvertisementInfo);
            return "family/advertisement/edit";
        }
        familyAdvertisementInfo.getFamilyAdvertisement().setMember(member);
        advertisementService.editFamilyAdvertisement(familyAdvertisementInfo.getFamilyAdvertisement());//UPDATE TWO
        return "redirect:/family/advertisement/edit/" + familyAdvertisementInfo.getFamilyAdvertisement().getId();
    }
以下是stacktrace:

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.bignibou.domain.FamilyAdvertisement#1]
    org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:303)
    org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
    org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
    org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:903)
    org.hibernate.internal.SessionImpl.merge(SessionImpl.java:887)
    org.hibernate.internal.SessionImpl.merge(SessionImpl.java:891)
    org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:879)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:601)
    org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
    com.sun.proxy.$Proxy45.merge(Unknown Source)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:601)
    org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241)
    com.sun.proxy.$Proxy44.merge(Unknown Source)
    org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:345)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:601)
    org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:334)
    org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:319)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:91)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    com.sun.proxy.$Proxy52.save(Unknown Source)
    com.bignibou.service.AdvertisementServiceImpl_Roo_Service.ajc$interMethod$com_bignibou_service_AdvertisementServiceImpl_Roo_Service$com_bignibou_service_AdvertisementServiceImpl$updateFamilyAdvertisement(AdvertisementServiceImpl_Roo_Service.aj:58)
    com.bignibou.service.AdvertisementServiceImpl.updateFamilyAdvertisement(AdvertisementServiceImpl.java:1)
    com.bignibou.service.AdvertisementServiceImpl_Roo_Service.ajc$interMethodDispatch1$com_bignibou_service_AdvertisementServiceImpl_Roo_Service$com_bignibou_service_AdvertisementServiceImpl$updateFamilyAdvertisement(AdvertisementServiceImpl_Roo_Service.aj)
    com.bignibou.service.AdvertisementServiceImpl.editFamilyAdvertisement(AdvertisementServiceImpl.java:27)
    com.bignibou.controller.AdvertisementController.editFamilyAdvertisement(AdvertisementController.java:85)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
编辑1

SQL日志:

2013-04-06 11:23:24,339 [http-bio-8080-exec-9] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public java.lang.String com.bignibou.controller.AdvertisementController.editFamilyAdvertisement(com.bignibou.controller.helpers.FamilyAdvertisementInfo,org.springframework.validation.BindingResult,org.springframework.ui.Model)]
Hibernate: 
    /* load com.bignibou.domain.GeolocationPostcode */ select
        geolocatio0_.id as id8_0_,
        geolocatio0_.postcode as postcode8_0_,
        geolocatio0_.version as version8_0_ 
    from
        geolocation_postcode geolocatio0_ 
    where
        geolocatio0_.id=?
Hibernate: 
    /* load com.bignibou.domain.Member */ select
        member0_.id as id6_1_,
        member0_.activated as activated6_1_,
        member0_.address as address6_1_,
        member0_.email as email6_1_,
        member0_.last_connection_date as last4_6_1_,
        member0_.password as password6_1_,
        member0_.registration_date as registra6_6_1_,
        member0_.role as role6_1_,
        member0_.token as token6_1_,
        member0_.version as version6_1_,
        address1_.id as id3_0_,
        address1_.formatted_address as formatted2_3_0_,
        address1_.latitude as latitude3_0_,
        address1_.longitude as longitude3_0_,
        address1_.version as version3_0_ 
    from
        member member0_ 
    left outer join
        address address1_ 
            on member0_.address=address1_.id 
    where
        member0_.id=?
Hibernate: 
    /* load one-to-many com.bignibou.domain.Member.advertisements */ select
        advertisem0_.member as member6_1_,
        advertisem0_.id as id0_1_,
        advertisem0_.id as id0_0_,
        advertisem0_.active as active0_0_,
        advertisem0_.creation_date as creation3_0_0_,
        advertisem0_.description as descript4_0_0_,
        advertisem0_.expiration_date as expiration5_0_0_,
        advertisem0_.member as member0_0_,
        advertisem0_.validated as validated0_0_,
        advertisem0_.version as version0_0_,
        advertisem0_.childminder_status as childmin1_10_0_,
        advertisem0_.clazz_ as clazz_0_ 
    from
        ( select
            id,
            active,
            creation_date,
            description,
            expiration_date,
            validated,
            version,
            member,
            null as childminder_status,
            1 as clazz_ 
        from
            family_advertisement 
        union
        select
            id,
            active,
            creation_date,
            description,
            expiration_date,
            validated,
            version,
            member,
            childminder_status,
            2 as clazz_ 
        from
            childminder_advertisement 
    ) advertisem0_ 
where
    advertisem0_.member=?
广告:

@RooJavaBean
@RooToString
@RooEquals
@RooJpaEntity(inheritanceType = "TABLE_PER_CLASS")
@Entity
@DynamicUpdate
public abstract class Advertisement {

    @ElementCollection
    private Set<ChildcareType> childcareTypes;

    @ManyToMany
    private List<DayToTimeSlot> dayToTimeSlots;

    @NotNull(groups = { Validation.AdvertisementCreation.class })
    @ManyToMany
    private Set<GeolocationPostcode> postcodes;

    @NotNull(groups = { Default.class })
    @Size(min = 6, max = 300, groups = { Default.class, Validation.AdvertisementCreation.class })
    @Column(length = 300)
    private String description;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(pattern = "dd/MM/yyyy HH:mm:ss")
    private Date creationDate;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(pattern = "dd/MM/yyyy HH:mm:ss")
    private Date expirationDate;

    @NotNull(groups = { Default.class })
    private boolean active;

    @NotNull(groups = { Default.class })
    private boolean validated;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    private Member member;

    public abstract boolean isChildcareTypesValid();

    @AssertTrue(groups = { Validation.AdvertisementCreation.class })
    public boolean isPostcodesValid() {
        return (postcodes != null && !postcodes.isEmpty());
    }

}
@RooJavaBean
@RooToString
@RooEquals
@RooJpaEntity
@Entity
@DynamicUpdate
public class FamilyAdvertisement extends Advertisement {

    @NotNull(groups = Validation.AdvertisementCreation.class)
    @ElementCollection
    private Set<Need> needs;

    @ElementCollection
    private Set<ChildminderStatus> childminderStatuses;

    @AssertTrue
    @Override
    public boolean isChildcareTypesValid() {
        return true;
    }

    @AssertTrue
    public boolean isNeedsValid() {
        if (needs.isEmpty()) {
            return false;
        }
        if (needs.contains(Need.CHILDMINDER_TO_FAMILY)) {
            return false;
        }
        return true;
    }

}
@RooJavaBean
@生根
@RooEquals
@RooJpaEntity(inheritanceType=“每个类的表”)
@实体
@动态铜日期
公共抽象类广告{
@元素集合
私人设置的儿童护理类型;
@许多
私有列表dayToTimeSlots;
@NotNull(组={Validation.AdvertisementCreation.class})
@许多
私人邮政编码;
@NotNull(组={Default.class})
@大小(最小值=6,最大值=300,组={Default.class,Validation.AdvertisementCreation.class})
@柱(长度=300)
私有字符串描述;
@时态(TemporalType.TIMESTAMP)
@日期时间格式(pattern=“dd/MM/yyyy HH:MM:ss”)
私人约会;
@时态(TemporalType.TIMESTAMP)
@日期时间格式(pattern=“dd/MM/yyyy HH:MM:ss”)
私人日期到期日期;
@NotNull(组={Default.class})
私有布尔活动;
@NotNull(组={Default.class})
私有布尔验证;
@NotNull
@manytone(fetch=FetchType.LAZY)
私人会员;
公共抽象布尔值isChildcareTypesValid();
@AssertTrue(组={Validation.AdvertisementCreation.class})
公共布尔值isPostcodesValid(){
return(postcodes!=null&&!postcodes.isEmpty());
}
}
家庭广告:

@RooJavaBean
@RooToString
@RooEquals
@RooJpaEntity(inheritanceType = "TABLE_PER_CLASS")
@Entity
@DynamicUpdate
public abstract class Advertisement {

    @ElementCollection
    private Set<ChildcareType> childcareTypes;

    @ManyToMany
    private List<DayToTimeSlot> dayToTimeSlots;

    @NotNull(groups = { Validation.AdvertisementCreation.class })
    @ManyToMany
    private Set<GeolocationPostcode> postcodes;

    @NotNull(groups = { Default.class })
    @Size(min = 6, max = 300, groups = { Default.class, Validation.AdvertisementCreation.class })
    @Column(length = 300)
    private String description;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(pattern = "dd/MM/yyyy HH:mm:ss")
    private Date creationDate;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(pattern = "dd/MM/yyyy HH:mm:ss")
    private Date expirationDate;

    @NotNull(groups = { Default.class })
    private boolean active;

    @NotNull(groups = { Default.class })
    private boolean validated;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    private Member member;

    public abstract boolean isChildcareTypesValid();

    @AssertTrue(groups = { Validation.AdvertisementCreation.class })
    public boolean isPostcodesValid() {
        return (postcodes != null && !postcodes.isEmpty());
    }

}
@RooJavaBean
@RooToString
@RooEquals
@RooJpaEntity
@Entity
@DynamicUpdate
public class FamilyAdvertisement extends Advertisement {

    @NotNull(groups = Validation.AdvertisementCreation.class)
    @ElementCollection
    private Set<Need> needs;

    @ElementCollection
    private Set<ChildminderStatus> childminderStatuses;

    @AssertTrue
    @Override
    public boolean isChildcareTypesValid() {
        return true;
    }

    @AssertTrue
    public boolean isNeedsValid() {
        if (needs.isEmpty()) {
            return false;
        }
        if (needs.contains(Need.CHILDMINDER_TO_FAMILY)) {
            return false;
        }
        return true;
    }

}
@RooJavaBean
@生根
@RooEquals
@RooJpaEntity
@实体
@动态铜日期
公共类家庭广告延伸广告{
@NotNull(组=Validation.AdvertisementCreation.class)
@元素集合
私人需求;
@元素集合
私人儿童保育员;
@资产真实
@凌驾
公共布尔值isChildcareTypesValid(){
返回true;
}
@资产真实
公共布尔值isNeedsValid(){
if(needs.isEmpty()){
返回false;
}
if(需要.包含(需要.儿童看护人至家庭)){
返回false;
}
返回true;
}
}
编辑2:我必须提到我使用SpringRoo+JPA默认提供的实体版本控制。我非常确定这一点必须考虑在内

编辑3:我已经建立了一个示例应用程序,在github上演示了这个问题。任何希望帮助我的人都可以按如下方式克隆该应用:
git clonehttps://github.com/balteo/sample-app-gab

“org.hibernate.StaleObjectStateException:行被另一个事务更新或删除(或未保存的值映射不正确):[com.bignibou.domain.FamilyAdvertisement#1]”提出问题的两个原因-一些意外的更新(考虑到您正在选择数据,这会很奇怪)或JPA映射中的错误


请添加由JPA生成的SQL查询日志记录和post SQL查询。请同时上家庭广告课。查询日志记录取决于JPA提供程序(请参阅此处以获取提示:)

我遇到了类似的问题。这是我在运行mvn测试时遇到的错误:


org.hibernate.StaleObjectStateException:行被另一个事务更新或删除(或未保存的值映射不正确)

这是因为,我错误地将实体的
version
字段初始化为
NULL

mysql> select * from lap;
+----+-------------+---------------------+------+------------------+---------+---------+
| id | code        | cumulative_distance | name | partial_distance | version | race_id |
+----+-------------+---------------------+------+------------------+---------+---------+
|  1 | AF0CUL00011 |                1000 | LAP1 |             1000 |    NULL |       1 |
|  2 | AQ000000012 |                2000 | LAP2 |             1000 |    NULL |       2 |
|  3 | AR000000013 |                3000 | LAP3 |             1000 |    NULL |       3 |
|  4 | AR0000N0114 |                4000 | LAP4 |             1000 |    NULL |       4 |
+----+-------------+---------------------+------+------------------+---------+---------+
4 rows in set (0.00 sec)
有一次,我用0初始化了
version
字段,一切正常:

mysql> select * from lap;
+----+-------------+---------------------+------+------------------+---------+---------+
| id | code        | cumulative_distance | name | partial_distance | version | race_id |
+----+-------------+---------------------+------+------------------+---------+---------+
|  1 | AF0CUL00011 |                1000 | LAP1 |             1000 |       0 |       1 |
|  2 | AQ000000012 |                2000 | LAP2 |             1000 |       0 |       2 |
|  3 | AR000000013 |                3000 | LAP3 |             1000 |       0 |       3 |
|  4 | AR0000N0114 |                4000 | LAP4 |             1000 |       0 |       4 |
+----+-------------+---------------------+------+------------------+---------+---------+
4 rows in set (0.00 sec)
我希望有帮助,
Agustin

您是否尝试过查看它的使用情况,您的会话范围似乎有问题。谢谢Mootinator。哪一行使您认为会话范围有问题?没有什么特别的,只是一种气味。考虑到你的情况,绝对不太可能出现映射问题。Mootinator:这是什么映射问题?我可以提供有关我的映射的更多信息吗?如果是,那又怎样?我已经编辑了我的帖子,并在github上包含了一个示例应用程序,演示了这个问题。嗨,Piotr。你能详细说明你所指的JPA映射中的错误类型吗?嗨,Piotr,我已经编辑了我的帖子,并在github上提供了一个示例应用程序来演示这个问题。