해결됨
자바 ORM 표준 JPA 프로그래밍 - 기본편
[SQL Error: 23503] Cascade 설정 후 Parent remove할 때 질문입니다.
안녕하세요! 이전 질문에서 영한님 답변을 받고 원인을 해결하여
다른 경우 또한 테스트해보고 있는데 SQL Error: 23503 에러가 발생했고, 구글링 결과 참조 키 제약조건 위배될 때 발생하는 에러라 하는데 아래 상황에서 왜 이 에러가 뜨는지 모르겠어서 질문을 남깁니다.
Parent, child 끼리 연관관계 매핑 후, cascadetype.ALL, orphanRemoval=false로 설정한 후, parent를 삭제할 때 발생한 에러입니다.
먼저 Parent, Child, Main 클래스 코드를 보여드리겠습니다!
@Entity
public class Parent {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<Child> children=new ArrayList<>();
public void addChild(Child child){
children.add(child);
child.setParent(this);
}
// getter, setter 생략했습니다
}
@Entity
public class Child {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
private Parent parent;
// getter, setter 메소드 생략했습니다
}
Parent 클래스, Child 클래스는 위와 같이 작성했으며, cascadetype.ALL로 설정해놓았고, 고아 객체 제거는 설정하지 않았습니다.
메인 코드는 아래와 같습니다.
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em=emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
Parent parent=new Parent();
parent.setName("kth990303");
Child child1=new Child();
child1.setName("kthbaby1");
Child child2=new Child();
child2.setName("kthbaby2");
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
em.flush();
em.clear();
Parent findParent = em.find(Parent.class, parent.getId());
System.out.println("===================1");
findParent.getChildren().remove(0);
em.remove(findParent);
System.out.println("===================3");
tx.commit();
} catch(Exception e){
e.printStackTrace();
tx.rollback();
} finally{
em.close();
}
emf.close();
}
}
역시 orphanRemoval=true가 아니었기 때문에 findParent.getChildren().remove(0);코드에서, 아무 일이 일어나지 않고 지연로딩으로 인한 child select 쿼리만 날라가는건 예상대로였는데, 문제는 그 아래 em.remove(findParent); 였습니다. 이미 em.find로 영속성 컨텍스트에 정보가 있어 parent를 지울 때 에러가 발생하지 않은 상태로 parent와 children 모두 지워질 줄 알았는데 아래 사진과 같은 에러가 발생했습니다.
사실 parent를 지울 때 그냥 findParent.getChildren().remove(0); 을 작성하지 않고 em.remove(findParent);만 하면 parent가 지워짐과 동시에 children도 모두 잘 지워지는 성공적인 결과가 보이긴 합니다만,,, 위와 같이 코드를 짠 후 실행했더니 SQL ERROR 23503이 뜨는 이유가 궁금하여 질문드립니다.
금쪽같은 주말에 질문을 좀 많이 하는 듯하네요 ㅠㅠ 죄송합니다. 그리고 감사합니다 :)
===================1
Hibernate:
select
children0_.parent_id as parent_i3_2_0_,
children0_.id as id1_2_0_,
children0_.id as id1_2_1_,
children0_.name as name2_2_1_,
children0_.parent_id as parent_i3_2_1_
from
Child children0_
where
children0_.parent_id=?
===================3
Hibernate:
/* delete hellojpa.Child */ delete
from
Child
where
id=?
Hibernate:
/* delete hellojpa.Parent */ delete
from
Parent
where
id=?
5월 15, 2021 8:20:45 오후 org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 23503, SQLState: 23503
5월 15, 2021 8:20:45 오후 org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Referential integrity constraint violation: "FKLH67J1N7X7GT59U0PBKWQH6O6: PUBLIC.CHILD FOREIGN KEY(PARENT_ID) REFERENCES PUBLIC.PARENT(ID) (1)"; SQL statement:
/* delete hellojpa.Parent */ delete from Parent where id=? [23503-199]
5월 15, 2021 8:20:45 오후 org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl release
INFO: HHH000010: On release of batch it still contained JDBC statements
javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:81)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104)
at hellojpa.JpaMain.main(JpaMain.java:43)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:65)
... 2 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3551)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3810)
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:124)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1352)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:443)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3202)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2370)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
... 1 more
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Referential integrity constraint violation: "FKLH67J1N7X7GT59U0PBKWQH6O6: PUBLIC.CHILD FOREIGN KEY(PARENT_ID) REFERENCES PUBLIC.PARENT(ID) (1)"; SQL statement:
/* delete hellojpa.Parent */ delete from Parent where id=? [23503-200]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:459)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
at org.h2.message.DbException.get(DbException.java:205)
at org.h2.message.DbException.get(DbException.java:181)
at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:373)
at org.h2.constraint.ConstraintReferential.checkRowRefTable(ConstraintReferential.java:390)
at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:265)
at org.h2.table.Table.fireConstraints(Table.java:1057)
at org.h2.table.Table.fireAfterRow(Table.java:1075)
at org.h2.command.dml.Delete.update(Delete.java:153)
at org.h2.command.CommandContainer.update(CommandContainer.java:198)
at org.h2.command.Command.executeUpdate(Command.java:251)
at org.h2.server.TcpServerThread.process(TcpServerThread.java:406)
at org.h2.server.TcpServerThread.run(TcpServerThread.java:183)
at java.lang.Thread.run(Unknown Source)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:457)
at org.h2.engine.SessionRemote.done(SessionRemote.java:607)
at org.h2.command.CommandRemote.executeUpdate(CommandRemote.java:237)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:200)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:154)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
... 21 more
5월 15, 2021 8:20:45 오후 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:h2:tcp://localhost/~/test]
Process finished with exit code 0