인프런 커뮤니티 질문&답변

emkemkemk님의 프로필 이미지
emkemkemk

작성한 질문수

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

영속성 전이(CASCADE)와 고아 객체

orphanRemoval = true 로 했을 때, delete 쿼리가 나가지 않는 문제

작성

·

1.8K

1

문제 상황


안녕하세요, orphanRemoval = true 로 했을 때, delete 쿼리가 나가지 않는 오류가 있어 질문드리게 되었습니다. 실습에 사용한 코드는 아래와 같습니다. (import 문은 제거하였습니다.)

@Entity
public class Parent {

   @Id
   @GeneratedValue
   @Column(name = "PARENT_ID")
   private Long id;

   private String name;

   @OneToMany(mappedBy = "parent", orphanRemoval = true)
   private List<Child> childList = new ArrayList<>();

   public void addChild(Child child) {
      this.childList.add(child);
      child.setParent(this);
   }

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public List<Child> getChildList() {
      return childList;
   }
}

@Entity
public class Child {

	@Id
	@GeneratedValue
	private Long id;

	private String name;

	@ManyToOne
	@JoinColumn(name = "PARENT_ID")
	private Parent parent;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Parent getParent() {
		return parent;
	}

	public void setParent(Parent parent) {
		this.parent = parent;
	}
}


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 {

			Child child1 = new Child();
			Child child2 = new Child();

			Parent parent = new Parent();
			parent.addChild(child1);
			parent.addChild(child2);

			em.persist(parent);
			em.persist(child1);
			em.persist(child2);

			em.flush();
			em.clear();

			Parent findParent = em.find(Parent.class, parent.getId());
			findParent.getChildList().remove(0);

			tx.commit();
		} catch (Exception e) {
			tx.rollback();
		} finally {
			em.close();
		}

		emf.close();
	}
}

위의 JpaMain.main() 을 실행했을 때, 아래와 같은 로그가 나옵니다. (DDL 옵션은 create 입니다.)

/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=57639:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/charsets.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/ext/cldrdata.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/ext/dnsns.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/ext/jaccess.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/ext/jfxrt.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/ext/localedata.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/ext/nashorn.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/ext/sunec.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/ext/zipfs.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/jce.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/jfr.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/jfxswt.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/jsse.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/management-agent.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/resources.jar:/Users/preferkim/Library/Java/JavaVirtualMachines/corretto-1.8.0_362/Contents/Home/jre/lib/rt.jar:/Users/preferkim/IdeaProjects/inflearn-spring/hello-jpa/target/classes:/Users/preferkim/.m2/repository/org/hibernate/hibernate-entitymanager/5.3.10.Final/hibernate-entitymanager-5.3.10.Final.jar:/Users/preferkim/.m2/repository/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar:/Users/preferkim/.m2/repository/org/hibernate/hibernate-core/5.3.10.Final/hibernate-core-5.3.10.Final.jar:/Users/preferkim/.m2/repository/org/javassist/javassist/3.23.2-GA/javassist-3.23.2-GA.jar:/Users/preferkim/.m2/repository/antlr/antlr/2.7.7/antlr-2.7.7.jar:/Users/preferkim/.m2/repository/org/jboss/jandex/2.0.5.Final/jandex-2.0.5.Final.jar:/Users/preferkim/.m2/repository/com/fasterxml/classmate/1.3.4/classmate-1.3.4.jar:/Users/preferkim/.m2/repository/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0.jar:/Users/preferkim/.m2/repository/org/dom4j/dom4j/2.1.1/dom4j-2.1.1.jar:/Users/preferkim/.m2/repository/org/hibernate/common/hibernate-commons-annotations/5.0.4.Final/hibernate-commons-annotations-5.0.4.Final.jar:/Users/preferkim/.m2/repository/javax/persistence/javax.persistence-api/2.2/javax.persistence-api-2.2.jar:/Users/preferkim/.m2/repository/net/bytebuddy/byte-buddy/1.9.5/byte-buddy-1.9.5.jar:/Users/preferkim/.m2/repository/org/jboss/spec/javax/transaction/jboss-transaction-api_1.2_spec/1.1.1.Final/jboss-transaction-api_1.2_spec-1.1.1.Final.jar:/Users/preferkim/.m2/repository/com/h2database/h2/1.4.199/h2-1.4.199.jar hellojpa.JpaMain
Feb 10, 2023 12:19:21 PM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [
	name: hello
	...]
Feb 10, 2023 12:19:21 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {5.3.10.Final}
Feb 10, 2023 12:19:21 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Feb 10, 2023 12:19:21 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
Feb 10, 2023 12:19:21 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
Feb 10, 2023 12:19:21 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: using driver [org.h2.Driver] at URL [jdbc:h2:tcp://localhost/~/test]
Feb 10, 2023 12:19:21 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {user=sa}
Feb 10, 2023 12:19:21 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Feb 10, 2023 12:19:21 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
Feb 10, 2023 12:19:21 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Feb 10, 2023 12:19:22 PM org.hibernate.cfg.AnnotationBinder processJoinedDiscriminatorProperties
WARN: HHH000457: Joined inheritance hierarchy [hellojpa.domain.item.Item] defined explicit @DiscriminatorColumn.  Legacy Hibernate behavior was to ignore the @DiscriminatorColumn.  However, as part of issue HHH-6911 we now apply the explicit @DiscriminatorColumn.  If you would prefer the legacy behavior, enable the `hibernate.discriminator.ignore_explicit_for_joined` setting (hibernate.discriminator.ignore_explicit_for_joined=true)
Hibernate: 
    
    drop table Album if exists
Hibernate: 
    
    drop table Book if exists
Hibernate: 
    
    drop table Child if exists
Hibernate: 
    
    drop table Item if exists
Hibernate: 
    
    drop table Locker if exists
Hibernate: 
    
    drop table Member if exists
Hibernate: 
    
    drop table Movie if exists
Hibernate: 
    
    drop table Parent if exists
Hibernate: 
    
    drop table Team if exists
Hibernate: 
    
    drop sequence if exists hibernate_sequence
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: 
    
    create table Album (
       artist varchar(255),
        ITEM_ID bigint not null,
        primary key (ITEM_ID)
    )
Hibernate: 
    
    create table Book (
       author varchar(255),
        isbn varchar(255),
        ITEM_ID bigint not null,
        primary key (ITEM_ID)
    )
Hibernate: 
    
    create table Child (
       id bigint not null,
        name varchar(255),
        PARENT_ID bigint,
        primary key (id)
    )
Hibernate: 
    
    create table Item (
       DTYPE varchar(31) not null,
        ITEM_ID bigint not null,
        name varchar(255),
        price integer not null,
        primary key (ITEM_ID)
    )
Hibernate: 
    
    create table Locker (
       LOCKER_ID bigint not null,
        name varchar(255),
        primary key (LOCKER_ID)
    )
Hibernate: 
    
    create table Member (
       MEMBER_ID bigint not null,
        createdBy varchar(255),
        createdDate timestamp,
        lastModifiedBy varchar(255),
        lastModifiedDate timestamp,
        USERNAME varchar(255),
        LOCKER_ID bigint,
        TEAM_ID bigint,
        primary key (MEMBER_ID)
    )
Hibernate: 
    
    create table Movie (
       actor varchar(255),
        director varchar(255),
        ITEM_ID bigint not null,
        primary key (ITEM_ID)
    )
Hibernate: 
    
    create table Parent (
       PARENT_ID bigint not null,
        name varchar(255),
        primary key (PARENT_ID)
    )
Hibernate: 
    
    create table Team (
       TEAM_ID bigint not null,
        createdBy varchar(255),
        createdDate timestamp,
        lastModifiedBy varchar(255),
        lastModifiedDate timestamp,
        name varchar(255),
        primary key (TEAM_ID)
    )
Hibernate: 
    
    alter table Member 
       add constraint UK_336xr48t7ci4jeiq7lt6xm2f4 unique (LOCKER_ID)
Hibernate: 
    
    alter table Album 
       add constraint FK75mrpprv8oigh00y92tibw7id 
       foreign key (ITEM_ID) 
       references Item
Hibernate: 
    
    alter table Book 
       add constraint FK2srbe8wjbanr4vtkrsb8atq7o 
       foreign key (ITEM_ID) 
       references Item
Hibernate: 
    
    alter table Child 
       add constraint FKqtrfkxtu92rllepi09f1mwvls 
       foreign key (PARENT_ID) 
       references Parent
Hibernate: 
    
    alter table Member 
       add constraint FK332130jlg9s5hyeuk7gfgi052 
       foreign key (LOCKER_ID) 
       references Locker
Feb 10, 2023 12:19:22 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@55caeb35] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Feb 10, 2023 12:19:22 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@3af37506] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: 
    
    alter table Member 
       add constraint FKl7wsny760hjy6x19kqnduasbm 
       foreign key (TEAM_ID) 
       references Team
Hibernate: 
    
    alter table Movie 
       add constraint FKqqwswm36y8uqoh9emtoruoxcv 
       foreign key (ITEM_ID) 
       references Item
Feb 10, 2023 12:19:22 PM org.hibernate.tool.schema.internal.SchemaCreatorImpl applyImportSources
INFO: HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@36a7abe1'
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    /* insert hellojpa.domain.cascade.Parent
        */ insert 
        into
            Parent
            (name, PARENT_ID) 
        values
            (?, ?)
Hibernate: 
    /* insert hellojpa.domain.cascade.Child
        */ insert 
        into
            Child
            (name, PARENT_ID, id) 
        values
            (?, ?, ?)
Hibernate: 
    /* insert hellojpa.domain.cascade.Child
        */ insert 
        into
            Child
            (name, PARENT_ID, id) 
        values
            (?, ?, ?)
Hibernate: 
    select
        parent0_.PARENT_ID as PARENT_I1_7_0_,
        parent0_.name as name2_7_0_ 
    from
        Parent parent0_ 
    where
        parent0_.PARENT_ID=?
Hibernate: 
    select
        childlist0_.PARENT_ID as PARENT_I3_2_0_,
        childlist0_.id as id1_2_0_,
        childlist0_.id as id1_2_1_,
        childlist0_.name as name2_2_1_,
        childlist0_.PARENT_ID as PARENT_I3_2_1_ 
    from
        Child childlist0_ 
    where
        childlist0_.PARENT_ID=?
Feb 10, 2023 12:19:22 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:h2:tcp://localhost/~/test]

Process finished with exit code 0

 

질문

Q. 저는 ParentorphanRemoval=true 로 설정되어있고, JpaMain.main() 에서 '부모 엔티티의 컬렉션에서 자식 엔티티의 참조를 제거' 하고 있으므로 당연히 DELETE 문이 나가야 하지 않나라고 생각했지만, 실제로는 DELETE 문이 나가지 않더라고요. 혹시 제가 잘못이해하고 있는 걸까요?

Q. Parentcascade = CascadeType.ALL 옵션을 추가하고 나면 DELETE 문이 정상적으로 나가는 것을 확인할 수 있었습니다. orphanRemoval=true 를 설정해주기만 DELETE 문이 나가야할 것 같은데, cascade = CascadeType.ALL 까지 추가해야 DELETE 문이 나가는 이유가 무엇인지 궁금합니다.

영한님과 서포터님들께 항상 감사드립니다.🙇‍♂️

답변 1

3

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. manhae님^^

orphanRemoval은 부모 엔티티를 삭제했을 때 해당 자식도 삭제되는 기능입니다.

다음 코드를 작성해보시면 이해가 되실거에요.

em.remove(findParent);

감사합니다.

emkemkemk님의 프로필 이미지
emkemkemk

작성한 질문수

질문하기