일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Spring Framework
- LiveTemplate
- Mockito #Reflection #Sigleton #Test #JUnit
- tomcat
- spring
- autocomplete
- 톰캣
- 디자인패턴 #싱글톤
- 외장톰캣
- Today
- Total
자라선
[자바 ORM 표쥰 JPA 프로그래밍] 17일차 - CASCADE & orphanRemoval 본문
JPA는 엔티티를 관리하기 위해 무조건 영속성 컨텍스트를 통해 관리가 이루어지는데
이는 테이블의 CASCADE와 같은 기능을 사용하여 엔티티도 똑같이 부모 엔티티를 통해 자식 엔티티를 관리할 수 있다.
1. CASCADE - INSERT
영속성 전이라고 부르며 부모 엔티티를 통해 자식 엔티티를 관리할 수 있도록 설정한다.
@Data
@Entity
public class Member { // 자식 엔티티
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private long id;
private String name;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY)
private List<Orders> orders = new ArrayList<Orders>();
}
@Data
@Entity
public class Team { // 부모 엔티티
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
}
// Team 엔티티를 영속성 컨텍스트에 저장
Team team = new Team();
team.setName("팀");
em.persist(team);
Member member = new Member();
member.setName("이름1");
member.setTeam(team); // 자식 엔티티 도한 부모와 관계를 맺은 후
em.persist(member); // 영속성 컨텍스트에 저장한다.
Member member1 = new Member();
member1.setName("이름2");
member1.setTeam(team);
em.persist(member1);
일반적으로는 엔티티를 DB에 INSERT 하고자 할때 부모 엔티티와 관계를 갖는 자식 엔티티 모두 EntityManager.persist 를 통해 영속성 컨텍스트에 등록을 해주어야한다.
하지만 CASCADE를 사용한다면 부모 엔티티만 등록하여도 관계를 갖는 자식엔티티 모두 등록이 된다.
@Data
@Entity
public class Team {
...
@OneToMany(mappedBy = "team", cascade = CascadeType.PERSIST) // CASCADE 설정 추가
private List<Member> members = new ArrayList<Member>();
}
@OneToMany 매핑 어노테이션에 cascade 속성을 추가하여 CascadeType.PERSIST 값을 지정해주었다.
// Team 엔티티를 영속성 컨텍스트에 저장
Team team = new Team();
team.setName("팀");
Member member = new Member();
member.setName("이름1");
Member member1 = new Member();
member1.setName("이름2");
// 자식 엔티티 2개 모두 부모 엔티티와 매핑을 맺는다.
member.setTeam(team); // 자식 엔티티 도한 부모와 관계를 맺은 후
member1.setTeam(team);
team.getMembers().add(member);
team.getMembers().add(member1);
em.persist(team);
위 코드를 보면 EntityManager.persist 를 Team 엔티티만 추가하였다.
관계만 맺게하고 Team 엔티티의 Members List에도 add 하여 엔티티를 넣어주어야한다.
이러면 부모 엔티티인 Team 의 자식 엔티티인 Member 모두 INSERT 처리가 된다.
이렇게 cascade 를 사용하여 물리적 관계를 맺은것은 연관관계 매핑과는 아무런 관계가 없으며 JPA에서는 관계된 테이블들만 영속성 컨텍스트로 끌고오는 편리함을 제공해주는 것 뿐이다.
+ 추가 1
INSERT 도 된다면 당연히 삭제 또한 가능하다.
@Data
@Entity
public class Team {
...
@OneToMany(mappedBy = "team", cascade = CascadeType.REMOVE) // CASCADE 설정 추가
private List<Member> members = new ArrayList<Member>();
}
cascade 설정을 REMOVE 로 한다면 부모 엔티티가 삭제가 된다면 이와 관계를 맺고있는 자식 엔티티들도 모두 삭제가 된다.
// TEAM_ID 가 26인 ROW를 DELETE
final Team team = em.find(Team.class, 26l);
em.remove(team); // Member에 team이 26인 ROW는 전부 DELETE
+ 추가 2
cascade 종류도 여러가지가 있다.
public enum CascadeType {
ALL, // 모두 적용
PERSIST, // 영속
MERGE, // 병합
REMOVE, // 삭제
REFRESH, // REFRESH
DETACH; // DETACH
private CascadeType() {
}
}
@OneToMany(mappedBy = "team", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
private List<Member> members = new ArrayList<Member>();
적용할때는 {} 를 사용하여 여러개를 cascade 를 적용할 수 있다.
2. orphanRemoval (고아 객체)
JPA는 부모 엔티티로부터 관계가 끊어진 자섹 엔티티를 자동으로 삭제할수 있도록 기능을 제공해준다.
이것을 고아 객체 제거라고 부른다.
@Data
@Entity
public class Team {
...
@OneToMany(mappedBy = "team", orphanRemoval = true) // 고아 객체도 제거할 수 있도록 명시
private List<Member> members = new ArrayList<Member>();
}
부모 엔티티에서 @OneToMany 의 매핑 어노테이션에 orphanRemoval 속성의 값을 true로 한다.
// TEAM_ID 가 23인 ROW를 SELECT
final Team team = em.find(Team.class, 23l);
// 참조 조회만 할수 있는 Member 프록시 리스트 객체를 반환
final Member member = team.getMembers().get(0);
System.out.println("member.getName() = " + member.getName());
em.remove(member); // 주인이 아닌 관계에서 참조를 제거만 해도 실제 DB에도 반영된다.
그리고 부모 객체를 조회 후 Member 컬렉션 래퍼에서 Member를 호출 후 EntityManager.remove 를 하였다.
원래 같으면 Team.members 는 참조용이기 때문에 영속성 컨텍스트와 아무런 관계도 없어 DB에 적용이 되면 안되지만 고아 객체 제거를 true로 하였기 때문에 가능하였다.
final Team team = em.find(Team.class, 23l);
// Team 엔티티는 조회하였지만 JPA는 members와 같은 컬렉션은 지연 로딩으로 인해 비어있는 프록시 컬렉션으로 만들어준다
// 이러한 프록시 컬렉션은 컬렉션 래퍼라고 부르며 프록시와 비슷한 역할을 해준다.
System.out.println(team.getMembers().getClass().getName()); // org.hibernate.collection.internal.PersistentBag
3. CASCADE + orphanRemoval 혼합
엔티티를 관리하기 위해서는 엔티티를 영속성 컨텍스트로 등록해야만 했고
등록하는 과정은 EntitiyManager.persist 와 같은 기능을 사용하였는데 위에서 보았던 CASCADE와 orphanRemoval을 혼합하여 사용한다면 관계를 가진 자식 엔티티는 부모 엔티티로 인해 관리를 할 수 있다.
@Data
@Entity
public class Team {
...
@OneToMany(mappedBy = "team", cascade = CascadeType.PERSIST, orphanRemoval = true)
private List<Member> members = new ArrayList<Member>();
}
@OneToMany 매핑 어노테이션에 CASCADE와 orphanRemoval 속성과 값을 추가
// CASCADE의 영속성 전이로 자식 엔티티또한 영속성 컨텍스트로 올려 INSERT
Team team = new Team();
Member member = new Member();
member.setTeam(team);
team.getMembers().add(member);
em.persist(team);
CASCADE 의 영속성 전이를 활용하여 자식 엔티티도 영속성 컨텍스트로 등록하여 INSERT를 한다.
// 부모 엔티티를 조회
final Team team = em.find(Team.class, 29l);
// 부모 엔티티와 관계를 맺고 있는 모든 자식 엔티티의 참조들을 제거함으로서 고아 객체 제거를 한다.
team.getMembers().clear();
그 후 부모 엔티티만 조회하고 부모 엔티티를 참조하고있는 모든 자식 엔티티를 clear() 시켜버림으로써
고아 객체 제거를 해 DELETE 하게된다.
이렇게 된다면 자식 엔티티는 EntitiyManager를 사용하지 않고도 관리를 할 수 있게 된다.
'Develop > JPA' 카테고리의 다른 글
[자바 ORM 표쥰 JPA 프로그래밍] 19일차 - JPQL (0) | 2021.09.08 |
---|---|
[자바 ORM 표쥰 JPA 프로그래밍] 18일차 - Value Type (0) | 2021.09.02 |
[자바 ORM 표쥰 JPA 프로그래밍] 16일차 - LAZY 로딩 & EAGER 로딩 (0) | 2021.09.02 |
[자바 ORM 표쥰 JPA 프로그래밍] 15일차 - 프록시 (0) | 2021.09.01 |
[자바 ORM 표쥰 JPA 프로그래밍] 14일차 - 복합키 매핑과 1:1 매핑 (0) | 2021.08.30 |