JPA:传递给persist的分离实体:嵌套异常是org.hibernate.PersistentObjectException

时间:2018-03-31 20:25:48

标签: hibernate spring-boot jpa spring-data-jpa many-to-many

JPA:多对多连接。

之情况:

可以在多个类别下保存多个产品。喜欢:芒果可以用作水果类和沙漠类。

  

产品== [商品]

     

类别== [GENRE]

例外:

detached entity passed to persist: sari.core.domain.account.Genre; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist:

Commodity.java:

@Entity
@Table(name = "COMMODITY")
public class Commodity implements Serializable {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    .........
    .........
    @ManyToMany(fetch = FetchType.LAZY,
            cascade = {
                    CascadeType.MERGE,
                    CascadeType.PERSIST
                })
    @JoinTable(name = "commodity_genre", joinColumns = {
            @JoinColumn(name = "commodity_id", referencedColumnName = "id") }, inverseJoinColumns = {
                    @JoinColumn(name = "genre_id", referencedColumnName = "id") })
    @JsonManagedReference
    private List<Genre> genres;

Genre.java:

@Entity
@Table(name = "GENRE")
public class Genre implements Serializable {

    private static final long serialVersionUID = 7643588406864492883L;

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    .........
    .........

    @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }, mappedBy = "genres")
    @JsonBackReference
    private List<Commodity> commodities;

我的行动计划:

  1. 检查您是否尝试持有具有相同ID的实体 作为另一个实体,已经存在于 应用程序中的PersistenceContext。
  2. 在保存或保留ID之前,请勿设置ID。 Hibernate会看 在您通过的实体,并假设因为它有它 主键填充它已在数据库中。各个 博客和人,使用删除setId()
  3. 给出了解决方案

    但没有运气。卡住了好几个小时。任何形式的帮助都非常感谢。

    资源链接:

    Hibernate / JPA – Detached entity passed to persist exception

    更多信息,您可以查看完整的异常日志:

    01-04-2018 00:55:39 [g.a.c.CommodityController:55] addCommodity : addCommodity() method started!!
    01-04-2018 00:55:39 [g.a.c.CommodityController:56] addCommodity : Full Model: Commodity [id=null, commodityName=Pant, price=345.0, unit=3, genres=null]
    01-04-2018 00:55:39 [g.a.c.CommodityController:57] addCommodity : Genre Name is: Cloth
    01-04-2018 00:55:39 [g.a.c.CommodityController:58] addCommodity : commodityName is: Pant
    01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:124] saveCommodities : saveCommodites called
    01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:113] checkGenreExistsInDB : checkGenreExistsInDB started
    Hibernate: select genre0_.id as id1_9_, genre0_.genre_name as genre_na2_9_ from genre genre0_ where genre0_.genre_name=?
    01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:118] checkGenreExistsInDB : checkGenreExistsInDB ended
    01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:133] saveCommodities : genre not Exists
    01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:135] saveCommodities : genre save in DB started
    Hibernate: insert into genre (genre_name) values (?)
    Hibernate: insert into commodity (commodity_name, price, unit) values (?, ?, ?)
    01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:137] saveCommodities : genre save in DB ended
    01-04-2018 00:55:39 [g.a.d.i.CommodityDaoImpl:140] saveCommodities : Size of genreList: 1
    Hibernate: insert into commodity (commodity_name, price, unit) values (?, ?, ?)
    01-04-2018 00:55:39 [g.c.u.GlobalExceptionHandler:58] runtimeExceptionHandle : org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: sari.core.domain.account.Genre; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: sari.core.domain.account.Genre
            at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:299)
            at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
            at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:488)
            at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
            at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
            at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
            at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
            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.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
            at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
            at com.sun.proxy.$Proxy160.save(Unknown Source)
            at sari.account.dao.impl.CommodityDaoImpl.saveCommodities(CommodityDaoImpl.java:142)
            at sari.account.services.CommodityService.saveCommodities(CommodityService.java:31)
            at sari.account.controllers.CommodityController.addCommodity(CommodityController.java:59)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
            at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
            at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116)
            at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
            at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
            at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
            at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
            at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
            at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
            at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
            at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
            at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
            at sari.core.util.CorsConfiguration.doFilterInternal(CorsConfiguration.java:29)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:208)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
            at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
            at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
            at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
            at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
            at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
            at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
            at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
            at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798)
            at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434)
            at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Thread.java:748)
    Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: sari.core.domain.account.Genre
            at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124)
            at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:765)
            at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:758)
            at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80)
            at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:398)
            at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
            at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:162)
            at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:431)
            at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:363)
            at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326)
            at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:162)
            at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:111)
            at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:456)
            at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:278)
            at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:178)
            at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:109)
            at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67)
            at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189)
            at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132)
            at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58)
            at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775)
            at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748)
            at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753)
            at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
            at com.sun.proxy.$Proxy156.persist(Unknown Source)
            at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:508)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504)
            at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489)
            at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
            at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
            at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
            at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
            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)
            ... 76 more
    
    01-04-2018 00:55:39 [g.c.u.GlobalExceptionHandler:77] <init> : Status: 200
    01-04-2018 00:55:39 [g.c.u.GlobalExceptionHandler:78] <init> : Message : detached entity passed to persist: sari.core.domain.account.Genre; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: sari.core.domain.account.Genre
    01-04-2018 00:55:39 [g.c.u.GlobalExceptionHandler:79] <init> : Trace: Resource Not Available
    

2 个答案:

答案 0 :(得分:4)

最后,我在JPA中获得了多对多连接的解决方案。

根本原因分析:

在JPA多对多关系中,如果已在CascadeType.PERSIST(或CascadeType.ALL(包括CascadeType.PERSIST)设置了级联类型,则在保存父级并使用引用更新它时孩子,它会试图再次拯救孩子。

可能会出现以下问题:

Child已经在持久性存储(A detached instance has been passed)中 - 在这种情况下,它将抛出异常“org.hibernate.PersistentObjectException: detached entity passed to persist”

解决方案:

使用此功能:

@ManyToMany(fetch = FetchType.EAGER,
        cascade = {
                CascadeType.MERGE,
                CascadeType.REFRESH
            })
@JoinTable(name = "commodity_genre", joinColumns = {
        @JoinColumn(name = "commodity_id", referencedColumnName = "id") }, inverseJoinColumns = {
                @JoinColumn(name = "genre_id", referencedColumnName = "id") })
@JsonManagedReference
private List<Genre> genres;

代替:

@ManyToMany(fetch = FetchType.LAZY,
        cascade = {
                CascadeType.MERGE,
                CascadeType.PERSIST
            })
@JoinTable(name = "commodity_genre", joinColumns = {
        @JoinColumn(name = "commodity_id", referencedColumnName = "id") }, inverseJoinColumns = {
                @JoinColumn(name = "genre_id", referencedColumnName = "id") })
@JsonManagedReference
private List<Genre> genres;

对于JPA,最好的选择是在尝试保存之前在服务器端查询实体。

  • 如果确定只添加新的孩子,而不是分离 来自DB的实例,CascadeType.PERSIST将负责处理它。
  • 另一方面,如果要求永远不会添加新的孩子 尚未进入数据库,则应删除CascadeType.PERSIST
  • 应该使用cascade={CascadeType.MERGE,CascadeType.REFRESH}

资源链接:

Persisting a detached entity in JPA

答案 1 :(得分:0)

对我来说,问题是使用Cascade.ALL而不是Cascade.MERGE