본문 바로가기

Back-End 공부/Spring

[스프링] dirtychecking(변경 감지)과 cascading(삽입, 삭제)

dirtychecking(변경 감지)

 

post를 수정하고 저장할 때, author 데이터도 자동으로 수정이 반영되게 만들어보자.

"수정" 작업을 통해 한 군데를 수정하고 저장했을 때, 그 한 쪽이 가지고 있는 다른 쪽이 연쇄되어 수정되는 것.

이 경우, authorRepository.save(author)를 해주지 않아도 JPA가 자동으로 변경사항을 반영해준다.

  • JPA는 트랜잭션이 커밋될 때 영속성 컨텍스트 내의 엔티티를 스캔하여 변경된 엔티티 검색
  • 변경된 엔티티가 감지되면, JPA는 save가 없어도 해당 변경 사항을 데이터베이스에 자동으로 반영

 

[ PostService.java ]

public void save(PostCreateReqDto postCreateReqDto){
    Author author = authorRepository.findByEmail(postCreateReqDto.getEmail()).orElse(null);
    Post post = Post.builder()
            .title(postCreateReqDto.getTitle())
            .contents(postCreateReqDto.getContents())
            .author(author)
            .build();

    //더티체킹 테스트
    author.updateAuthor("dirty checking test", "1234");
    postRepository.save(post);
}

 

게시글을 수정하면, 수정하고 있는 author의 이름이 dirty checking test, 비밀번호 1234로 변경된다.

 

 

기존에 가입 이력이 있는 이메일인 yd@naver.com이 쓴 글을 수정한다.

 

 

yd@naver.com이 쓴 글을 수정하게 되면,

author 객체의 name은 dirty checking test로, password는 1234로 자동으로 변경된다.

 

더티체킹이 되지 않는다면

authorRepository.save(author); 코드를 통해 author의 변경사항도 DB에 수정해줘야 한다.

 

 

 

 

cascading

 

 

"삽입, 삭제" 작업을 수행했을 때, 수정한 쪽과 관련된 다른 쪽이 연쇄되어 수정되는 것

  • Cascade를 사용하면, 부모 엔티티를 저장할 때 자동으로 연관된 자식 엔티티들도 함께 저장함으로서 코드를 간결하게 만들고, 엔티티 간의 관계를 명확하게 표현
  • 더티체킹과 비교하면 더티체킹은 변경사항에 대해서만 반영하지만 cascade옵션을 통해서는 연관엔티티의 신규 사항 추가 가능
  • Cascade 옵션은 일반적으로 부모 엔티티에 설정한다.
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL, fetch=FetchType.LAZY) //Post 객체에 있는 변수명을 적어 매핑관계 표현
private List<Post> posts; // posts 리스트에 post가 생성될 때마다 Post 테이블 가서 생성해줌
//AuthorRepository.save만 해줘도 자동으로 PostRepository.save까지 해줌

 

 

[ AuthorService.java ]

public void save(AuthorSaveReqDto authorSaveReqDto) {
        Role role = null;
        if(authorSaveReqDto.getRole() == null || authorSaveReqDto.getRole().equals("user")){
            role = Role.USER;
        }else{
            role = Role.ADMIN;
        }
        //일반 생성자 방식
        //Author author = new Author(authorSaveReqDto.getName(), authorSaveReqDto.getEmail(), authorSaveReqDto.getPassword(), role);

        //빌더패턴
        // .build() : 최종적으로 완성시키는 단계
        Author author = Author.builder()
                .email(authorSaveReqDto.getEmail())
                .name(authorSaveReqDto.getName())
                .password(authorSaveReqDto.getPassword())
                .build();

//        //cascade.persist 테스트
        //부모 테이블을 통해 자식 테이블에 객체를 동시에 생성
        List<Post> posts = new ArrayList<>();
        Post post = new Post.builder()
                .title("안녕하세요. " + author.getName() + "입니다.")
                .contents("반갑습니다. cascade 테스트 중입니다..")
                .author(author)
                .build();
        posts.add(post);
        author.setPosts(posts); // setter를 사용하지 않기 위해 Post 생성자에 this.author.getPosts(this);
        //위 post 생성 주석을 풀 경우, author만 save해줘도 post까지 save됨 => cascade ⭐
        authorRepository.save(author);
    }

author객체에 posts객체를 set하여 author객체를 save할 경우 cascade옵션이 설정돼 있으면 post객체에도 save된다.