当前位置: 首页 > 知识库问答 >
问题:

使用spring data jpa来更新实体(无需逐个复制字段)

凌啸
2023-03-14

我有一个address的新的/非托管实例和一个member的托管实例作为参数传递给以下方法:

@Override
public void modifyAddress(Member member, Address address){
    long addressId = member.getAddress().getId();//retrieving id of managed address instance
    address.setId(addressId);//setting id on unmanaged instance
    updateAddress(address);//updating unmanaged instance
}

UpdateAddress方法的实现:

 public Address PreferencesServiceImpl.updateAddress(Address address) {
        return addressRepository.save(address);
 }

正如您所看到的,我正在尝试更新地址,JPA出现以下异常:

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.bignibou.domain.Address#5]
    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.$Proxy122.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.$Proxy121.merge(Unknown Source)
    org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:353)
    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:333)
    org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:318)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    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:92)
    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.$Proxy137.save(Unknown Source)
    com.bignibou.service.PreferencesServiceImpl_Roo_Service.ajc$interMethod$com_bignibou_service_PreferencesServiceImpl_Roo_Service$com_bignibou_service_PreferencesServiceImpl$updateAddress(PreferencesServiceImpl_Roo_Service.aj:81)
    com.bignibou.service.PreferencesServiceImpl.updateAddress(PreferencesServiceImpl.java:1)

编辑1:

我已经设置了一个示例应用程序来再现该问题。任何希望使用示例github应用程序重现问题的人都需要:

  • Maven
  • Git
  • JDK 6
  • MySQL
    null

有谁能向我解释为什么在我的情况下会出现这个异常,以及如何更新地址实例而不得到这个异常吗?

共有1个答案

徐洋
2023-03-14

long addressId=member.getAddress().getID();

数据库中已经保存了一个Member实例,并且它与数据库中已经保存的Address实例有外键关系。FK关系通过member.getAddress()在对象模型中导航。Address实例的主键是member.getAddress().getId()。

address.setid(addressId)

您已经在对象模型中创建了Address的另一个新实例,并手动设置为与保存在数据库中的先前存在的实例相同的主键,然后尝试保存新实体。

这是违法的。如果您希望更新一个预先存在的实体,您必须加载它,启动一个事务,修改属性并提交事务。如果希望添加新实体,则必须启动事务、创建新实例、填充其属性(包括新的唯一主键)、保存它并提交事务。

您可以通过在PK属性上使用JPA@id注释加上@generatedvalue注释(在代码的其他地方加上@sequenceGenerator/@tableGenerator注释(通常是在类上),自动填充新的唯一PK值。以下是两个教程:http://www.oracle.com/technetwork/middleware/ias/id-generation-083058.html http://www.objectdb.com/java/jpa/entity/generated

 类似资料:
  • 如何使用Spring Rest Controller和Spring Data JPA仅更新从@刚体传递的实体属性? 员工实体: 服务类方法: 请求体: Hibernate更新查询: Spring Data JPA正在尝试将company_id设置为空以进行更新,即使我没有将其传递给请求体?但是如果我从数据库中得到实体,使用employee_id传递,然后如果我试图保存(),那么它的工作正常。 我想

  • 在Symfony 2(最新版本)下,我试图更新我的实体: 我得到了这个错误消息到我的终端: [Symfony\Component\Config\Definition\Exception\InvalidConfigurationException] 无法识别的选项“security.firewalls.access\u control”下的“0、1、2、3” 我是Symfony的新手,我不知道在哪里

  • 问题内容: 这是表 用户数 和代码.. 问题答案: Ladislav的答案已更新为使用DbContext(在EF 4.1中引入):

  • 我想在我的应用程序中使用自定义字体。这是为整个应用程序提供字体的最佳方式。我知道如何将自定义字体分配给单个文本视图或按钮。 是否可以在一个地方提到自定义字体,例如在样式中。xml,字体将应用于整个应用程序(每个文本视图、按钮、编辑文本等)。

  • 当我尝试更新一个实体的一个字段时,我是新来的,我注意到在日志中Hibernate执行两个查询,在更新之前,它会对所有字段进行SELECT。可以吗?为什么Hibernate执行SELECT?我如何用一个UPDATE查询更新一个字段?此外,当我试图更新一个实体中的单个标题时,它有另一个嵌套实体,我最终得到了一堆SELECT。我认为这对性能不好,或者我错了? 在互联网上,我找到了使用 @Modifyin

  • 我有一个User类,它有一些附加属性: 现在,如果我调用一些方法来改变其中一个房子(例如改变它的名称属性),如果我调用,我仍然会得到房子的旧值: 我如何确保它总是更新?