inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

자바 ORM 표준 JPA 프로그래밍 - 기본편

[SQL Error: 23503] Cascade 설정 후 Parent remove할 때 질문입니다.

해결된 질문

1431

TaeHyeon Kim

작성한 질문수 18

0

안녕하세요! 이전 질문에서 영한님 답변을 받고 원인을 해결하여

다른 경우 또한 테스트해보고 있는데 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

cascade remove java 23503 JPA

답변 1

4

김영한

안녕하세요. TaeHyeon Kim님

이 부분은 오류가 발생할 수 있습니다.

부모를 삭제했을 때 cascade로 자식들을 먼저 모두 삭제하고 부모를 삭제합니다.

그런데 현재 자식중의 하나를 remove(0)로 강제로 제거했기 때문에

부모 엔티티는 하나의 자식 엔티티만 가지고 있습니다.

하나의 자식만 가진 것으로 판단하고 가지고 있는 자식만 cascade로 삭제합니다.

그리고 본인도 삭제합니다. 이때 데이터베이스에서 처음 강제로 삭제한 엔티티는 아직 자식이 남아있기 때문에 삭제가 안되는 제약조건 오류가 발생한 것입니다.

그래서 이렇게 사용하실 때는 지금처럼 자식을 강제로 삭제하시면 안됩니다.

도움이 되셨길 바래요^^

벌크연산에서 member.getAge 호출 시 영속성 컨텍스트에서 데이터를 가져오는건가요?

0

14

2

inheritance startegy 선택시 고려사항

0

20

1

Entity 동등성 비교

0

17

1

실무 조언 관련 질문입니다.

0

44

1

H2데이터베이스 파일 생성

0

55

2

서브쿼리 강의에서 ALL 예시 관련 질문드립니다.

0

52

2

수정또는 삭제시 영속성 엔티티에 값이 무조건 있어야 하나요?

0

51

1

JPQL 메소드와 락

0

55

1

Delivery @OneToOne

0

60

1

17강 4~5분대 테이블 값 조회가 안됩니다.

0

92

2

UnsupportedOperationException 발생

0

85

3

H2 Database 연결이 안됩니다.

0

92

2

연관관계 매핑 질문드립니다.

0

84

2

h2데이터베이스 실행오류

0

107

2

persistence.xml

0

106

2

양방향 연관관계에서 연관관계의 주인(mappedBy)을 왜 꼭 정해야 하나요?

0

80

1

영속성 컨텍스트

0

64

1

JPA 프록시

0

94

1

Native Query와 MyBatis

0

66

1

영속성 컨텍스트는 어떤 메모리에 저장되는건가요?

0

85

1

임베디드 타입 예시 코드 관련 질문

0

114

3

명시적 조인에서 별칭을 주면 왜 객체에 접근할 수 있나요

0

93

3

인텔리제이 패키지 커서 단축키 질문

0

108

2

혹시 현재는 ID 데이터 타입이 String이면 안되나요?

0

142

1