Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

Cascade (영속성 전이) 본문

JPA/영속성 전이

Cascade (영속성 전이)

Seung__ 2021. 7. 6. 22:55

1. Cascade란?


영속성 전이로, Entity의 상태(생애주기)의 변화가 있을 때 연관 관계의 entity에 상태변화(생애주기)를 전파한다.

즉 Cascade는 연관관계의 entity에 영속성을 전이시켜준다.
따라서 @OneToOne, @OneToMany 등 과 같이 연관관계가 있을 때 설정할 수 있다.

Entity 생애 주기

bsh6463/BookManager Contribute to bsh6463/BookManager development by creating an account on GitHub. github.com 1. 비영속상태, new, transient 영속성 컨텍스트가 해당 엔티티 객체를 관리하지 않는 상태 @..

bsh-developer.tistory.com



2. Cascade 설정 6가지


기본 상태는 영속성 전이 없음.

ALL 아래 속성 모두 포함. 항상 영속성 전이.
PERSIST 부모 persist시 연관 entity도 persist
MERGE Transaction종료 후 detach 상태에서 연관 entity 수정/추가 후
부모 entity가 merge()를 하면 연관 entity의 변경, 추가내용 저장됨.
REMOVE 삭제 시 연관 entity도 삭제
REFRESH entity를 다시 로드했을 때, 연관관계 entity도 같이 로드
DETATCH 영속성 관리하지 않겠다. detatch 시점에 함께 detach
public enum CascadeType { /** Cascade all operations */ ALL, /** Cascade persist operation */ PERSIST, /** Cascade merge operation */ MERGE, /** Cascade remove operation */ REMOVE, /** Cascade refresh operation */ REFRESH, /** * Cascade detach operation * * @since 2.0 * */ DETACH }


연관관계를 활용해야 한다. book, publisher를 이용한다!
Book과 Publisher의 연관관계는 N : 1 이다.(Book : Publisher = Many : one)
Setter를 통해 연관관계를 맺어주고, publicshet에서 book을 주입할 때는 list로 입력해야 한다.
따라서 getBooks를 통해 book list를 가져오고 add를 해주는 방법으로 진행한다.

하지만 영속성 전이 test를 위해 publisher에 book 추가 및 save는 주석처리한다.

<BookRepositoryTest>

@Transactional @Test public void bookCascadeTest(){ Book book = new Book(); book.setName("JPA 공부하자"); Publisher publisher = new Publisher(); publisher.setName("패스트캠"); book.setPublisher(publisher); bookRepository.save(book); //publisher.getBooks().add(book); //set이 더 직관적임 ㅋㅋㅋㅋ //publisher.addBook(book); //publisherRepository.save(publisher); System.out.println("books : " + bookRepository.findAll()); System.out.println("publishers : " + publisherRepository.findAll()); } }


<Publisher>

 public void addBook(Book book){ this.books.add(book); }


이 상태로 test를 돌리면 에러가 난다.

object references an unsaved transient instance

Book, Publisher가 영속성 관리가 되지 않은 상태에서, Book에 Publisher를 넣으면 연관관계를 맺어주기 힘들기 때문.

이 상태에서 cascade옵션을 넣어주자!



3. PERSIST


<Book> : PERSIST(=Insert)에 대해 영속성 전이를 일으키겠다.
Book이 PERSIST될 때 Publisher도 PERSIST시켜라!

 @ManyToOne(cascade = CascadeType.PERSIST) @ToString.Exclude private Publisher publisher;


실행 결과 publicsher를 save하지 않았는데 insert query가 실행됨

book이 PERSIST 될 때 publisher도 같이 PERSIST 되었다.

Hibernate: insert into publisher (created_at, updated_at, name) values (?, ?, ?)


4. MERGE


publisher가 영속화 된 후 다시 불러와서 수정 & save() 해보자.

@Transactional @Test public void bookCascadeTest(){ Book book = new Book(); book.setName("JPA 공부하자"); Publisher publisher = new Publisher(); publisher.setName("패스트캠"); book.setPublisher(publisher); bookRepository.save(book); System.out.println("books : " + bookRepository.findAll()); System.out.println("publishers : " + publisherRepository.findAll()); Book book1 = bookRepository.findById(1L).get(); book1.getPublisher().setName("탐사수"); bookRepository.save(book1); System.out.println("publishers : " + publisherRepository.findAll()); }


Book이 Persist될 때만 Publisher도 PERSIST 될 것 같은데..?

Publisher가 udpate되었다...?

Hibernate: update publisher set created_at=?, updated_at=?, name=? where id=? Hibernate: select publisher0_.id as id1_4_, publisher0_.created_at as created_2_4_, publisher0_.updated_at as updated_3_4_, publisher0_.name as name4_4_ from publisher publisher0_ publishers : [Publisher(super=BaseEntity(createdAt=2021-07-06T21:50:38.417027900, updatedAt=2021-07-06T21:50:38.650754200), id=1, name=탐사수, books=[])]


사실 Cascade 옵션을 배열로 여러 개를 넣을 수 있는 걸 보려고 했는데...

@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})

원인은 lazyInitializationException을 처리하려고 추가한 @Transactinal인 것 같다.

* 만약 method에 @Transactional이 적용되면
jpql(findAll())실행 시 commit 후 select query가 실행된딘. 따라서 위의 결과는 autoFLush에 의해 해당 내용이 DB에 반영되고 select query가 실행된 결과이다.

* 해결
1) bookCascadeTest()의 @Transaction을 지우고

2) <Publisher> : Publisher에서 books에 대해 순환참고 끊기 위해 @ToString.Exclude 적용

 @OneToMany @JoinColumn(name = "publisher_id") @ToString.Exclude private List<Book> books = new ArrayList<>();

3) <Book> : MERGE 삭제

 @ManyToOne(cascade = {CascadeType.PERSIST}) @ToString.Exclude private Publisher publisher;

4)결과 : 의도한 대로 결과가 나왔다. PERSIST는 MERGE OPERATION에 대해 대응이 안된다.

publishers : [Publisher(super=BaseEntity(createdAt=2021-07-06T22:38:26.183082, updatedAt=2021-07-06T22:38:26.183082), id=1, name=패스트캠)]

5) <Book>에서 cascade 옵션에 MERGE를 추가하면.

@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})

book의 Merge operation에 대해 publisher도 merge가 된다.


5. GitHub : 210706 Cascade


bsh6463/BookManager

Contribute to bsh6463/BookManager development by creating an account on GitHub.

github.com

Comments