org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist

问题:

org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: org.hibernate.PersistentObjectException: detached entity passed to persist: 
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:319)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:531)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:154)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor

.
CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:178)atorg.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)atorg.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)atorg.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)atorg.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)atcom.sun.proxy.Proxy172.save(Unknown Source)

at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:120)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:110)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:744)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:712)
at org.hibernate.engine.spi.CascadingActions

7.cascade(CascadingActions.java:298)atorg.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:499)atorg.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:423)atorg.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:220)atorg.hibernate.engine.internal.Cascade.cascade(Cascade.java:153)atorg.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:427)atorg.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:264)atorg.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)atorg.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:123)atorg.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:185)atorg.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:128)atorg.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:55)atorg.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:99)atorg.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:720)atorg.hibernate.internal.SessionImpl.persist(SessionImpl.java:706)atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)atjava.lang.reflect.Method.invoke(Method.java:498)atorg.springframework.orm.jpa.SharedEntityManagerCreatorSharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:314)
at com.sun.proxy.

Proxy158.persist(UnknownSource)atorg.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:554)atsun.reflect.GeneratedMethodAccessor174.invoke(UnknownSource)atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)atjava.lang.reflect.Method.invoke(Method.java:498)atorg.springframework.data.repository.core.support.ImplementationInvocationMetadata.invoke(ImplementationInvocationMetadata.java:72)atorg.springframework.data.repository.core.support.RepositoryCompositionRepositoryFragments.invoke(RepositoryComposition.java:382)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:205)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:550)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:155)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:130)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
... 10 more

解决
这个异常堆栈信息显示了一个常见的Hibernate问题,即尝试持久化一个已经处于分离状态(detached)的实体对象。在Hibernate中,当一个实体对象从会话(Session)中取出并关闭了该会话后,该实体就会变成分离状态,此时再尝试对其进行更新或保存操作将会抛出PersistentObjectException异常。

解决这个问题的方法通常有以下几种:

1.重新关联(Re-attach)实体:
如果你在一个新的事务中处理这个已分离的实体,你需要先将其重新关联到当前的Hibernate Session。可以使用EntityManager.merge()方法将分离的实体合并回持久层上下文,这样就能对它进行更新和保存操作。
Java

Data detachedData = ...; // 已经分离的实体
Data managedData = entityManager.merge(detachedData);
repository.save(managedData); // 现在可以安全地保存

2.确保实体始终关联于Session:
在整个业务逻辑处理过程中,确保实体始终保持与Hibernate Session的关联状态,避免过早关闭Session或者使实体脱离Session管理。

3.检查代码逻辑:
请仔细审查你的代码,确保在调用save()方法之前没有意外地从数据库加载一个新的、未被修改过的DeviceData实例,并尝试覆盖已存在的、处于分离状态的实例。如果存在这种情况,需要调整代码逻辑以正确处理实体对象的状态。

4.级联策略(Cascade):
检查你的实体类之间的关系映射,尤其是涉及到级联操作的地方,确认是否因为错误的级联策略导致了此问题。例如,如果你不希望在保存某个实体时自动持久化其关联的Data,则需确保相关映射注解如@OneToMany或@OneToOne中的cascade属性设置正确