[SPRING] JPA는 분리 된 객체를 삭제한다고 생각합니다.
SPRINGJPA는 분리 된 객체를 삭제한다고 생각합니다.
JPA를 사용하여 도메인 객체를로드하고 저장하는 데 사용한 DAO가 있습니다. 마침내 트랜잭션 작업을 처리 할 수있게되었지만 이제는 또 다른 문제가 있습니다.
내 테스트 케이스에서, 나는 주어진 DA와 함께 도메인 객체를로드하고로드되었는지 확인한 다음 동일한 DAO를 호출하여 방금로드 한 객체를 삭제하도록 DAO를 호출한다. 내가 그렇게 할 때 나는 다음과 같은 것을 얻는다.
java.lang.IllegalArgumentException: Removing a detached instance mil.navy.ndms.conops.common.model.impl.jpa.Group#10
at org.hibernate.ejb.event.EJB3DeleteEventListener.performDetachedEntityDeletionCheck(EJB3DeleteEventListener.java:45)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:108)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:74)
at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:794)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:772)
at org.hibernate.ejb.AbstractEntityManagerImpl.remove(AbstractEntityManagerImpl.java:253)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:600)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:180)
at $Proxy27.remove(Unknown Source)
at mil.navy.ndms.conops.common.dao.impl.jpa.GroupDao.delete(GroupDao.java:499)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:600)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy28.delete(Unknown Source)
at mil.navy.ndms.conops.common.dao.impl.jpa.GroupDaoTest.testGroupDaoSave(GroupDaoTest.java:89)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:600)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:230)
at junit.framework.TestSuite.run(TestSuite.java:225)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
이제는 동일한 DAO 인스턴스를 사용하고 EntityManagers를 변경하지 않았습니다 (스프링이 알려주지 않으면 않는 한), 분리 된 객체는 어떻게 될까요?
내 DAO 코드는 다음과 같습니다.
public class GenericJPADao<INTFC extends IAddressable, VO extends BaseAddressable> implements IWebDao, IDao<INTFC>, IDaoUtil<INTFC>
{
private static Logger logger = Logger.getLogger (GenericJPADao.class);
protected Class<?> voClass;
@PersistenceContext(unitName = "CONOPS_PU")
protected EntityManagerFactory emf;
@PersistenceContext(unitName = "CONOPS_PU")
protected EntityManager em;
public GenericJPADao()
{
super ( );
ParameterizedType genericSuperclass =
(ParameterizedType) getClass ( ).getGenericSuperclass ( );
this.voClass = (Class<?>) genericSuperclass.getActualTypeArguments ( )[1];
}
...
public void delete (INTFC modelObj, EntityManager em)
{
em.remove (modelObj);
}
@SuppressWarnings("unchecked")
public INTFC findById (Long id)
{
return ((INTFC) em.find (voClass, id));
}
}
테스트 케이스 코드는 다음과 같습니다.
IGroup loadedGroup = dao.findById (group.getId ( ));
assertNotNull (loadedGroup);
assertEquals (group.getId ( ), loadedGroup.getId ( ));
dao.delete (loadedGroup); // - This generates the above exception
loadedGroup = dao.findById (group.getId ( ));
assertNull(loadedGroup);
아무도 내가 여기서 뭘 잘못하고 있다고 말할 수 있습니까?
해결법
-
==============================
1.나는 당신이 트랜잭션 외부에서 코드를 실행하고 있다고 판단하여 찾기와 삭제 작업이 별도의 영속 컨텍스트에서 이루어지며 find가 실제로 분리 된 인스턴스를 반환한다. 그래서 JPA가 맞고 분리 된 객체를 삭제하고있다.
나는 당신이 트랜잭션 외부에서 코드를 실행하고 있다고 판단하여 찾기와 삭제 작업이 별도의 영속 컨텍스트에서 이루어지며 find가 실제로 분리 된 인스턴스를 반환한다. 그래서 JPA가 맞고 분리 된 객체를 삭제하고있다.
트랜잭션 내에서 찾기 / 삭제 시퀀스를 래핑하십시오.
업데이트 : 7.3.1 장의 발췌 부분 아래 트랜잭션 지속성 컨텍스트 :
-
==============================
2.
public void remove(Object obj){ em.remove(em.merge(obj)); }
위의 코드는 zawhtut에서 제안한 코드와 비슷합니다.
-
==============================
3.+1 파스칼 Thivent의 게시물과 후속 조치.
+1 파스칼 Thivent의 게시물과 후속 조치.
@Transactional public void remove(long purchaseId){ Purchase attached = jpaTemplate.find(Purchase.class,purchaseId); jpaTemplate.remove(attached); }
-
==============================
4.em.find () 대신 em.getReference ()를 사용하여 인스턴스를 가져옵니다.
em.find () 대신 em.getReference ()를 사용하여 인스턴스를 가져옵니다.
예를 들어, 다음을 시도하십시오.
em.remove(em.getReference(INTFC.class, id));
-
==============================
5.여기에 내가 사용했던 것이있다 (이전의 대답에 기초하여)
여기에 내가 사용했던 것이있다 (이전의 대답에 기초하여)
public void deleteTask(int taskId) { Task task = getTask(taskId); //this is a function that returns a task by id if (task == null) { return; } EntityManager em = emf.createEntityManager(); EntityTransaction et = em.getTransaction(); et.begin(); em.remove(em.merge(task)); et.commit(); em.close(); }
-
==============================
6.트랜잭션은 ACID 속성을 보장하지만 엔티티가 연결되어 있거나 분리되어 있는지 여부는 보장하지 않습니다. 동일한 트랜잭션에서 entityManager.find 및 entityManager.remove ()를 실행하는 경우 엔티티가 연결된다는 보장이 없습니다. 따라서 entityManager.remove ()를 실행하기 전에 엔티티가 첨부되어 있는지 확인하고, enitityManger.merge (엔티티)를 사용하여 엔티티를 첨부하지 않았다면 엔티티가 첨부되었는지 확인한 후 다음과 같이 entityManager.remove를 실행하십시오.
트랜잭션은 ACID 속성을 보장하지만 엔티티가 연결되어 있거나 분리되어 있는지 여부는 보장하지 않습니다. 동일한 트랜잭션에서 entityManager.find 및 entityManager.remove ()를 실행하는 경우 엔티티가 연결된다는 보장이 없습니다. 따라서 entityManager.remove ()를 실행하기 전에 엔티티가 첨부되어 있는지 확인하고, enitityManger.merge (엔티티)를 사용하여 엔티티를 첨부하지 않았다면 엔티티가 첨부되었는지 확인한 후 다음과 같이 entityManager.remove를 실행하십시오.
@Transactional public void delete (long id) { ModelObj modelObj=entityManager.find(ModelObj.class,id); modelObj=entityManager.contains(modelObj)?modelObj:entityManager.merge(modelObj); em.remove (modelObj); }
from https://stackoverflow.com/questions/2428706/jpa-thinks-im-deleting-a-detached-object by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 스프링 MVC : 경로 변수가 필요한지 여부를 나타내는 방법? (0) | 2019.02.01 |
---|---|
[SPRING] spring-boot-startter-web을 사용하여 "수용 가능한 표현을 찾을 수 없습니다" (0) | 2019.02.01 |
[SPRING] @Component로 클래스에 주석을 달 때 Spring Bean과 Singleton을 의미합니까? (0) | 2019.02.01 |
[SPRING] 어떻게 봄을 사용하여 다시 브라우저 버튼 문제를 처리 할 수 있습니까? (0) | 2019.02.01 |
[SPRING] Spring DI applicationContext.xml xsi : schemaLocation은 정확히 어떻게 사용됩니까? (0) | 2019.01.31 |