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
관리 메뉴

개발자되기 프로젝트

Dirtycheck, 성능이슈 본문

JPA/Trouble shooting

Dirtycheck, 성능이슈

Seung__ 2021. 7. 12. 00:37

 

<commentService class>

@Service
public class CommentService {

    @Autowired
    private CommentRepository commentRepository;

    @Transactional
    public void innit(){

        for(int i=0; i<10; i++){
            Comment comment = new Comment();
            comment.setComment("오우야");

            commentRepository.save(comment);
        }
    }

    @Transactional
    public void updateSomething(){

        List<Comment> comments = commentRepository.findAll();

        for(Comment comment : comments){

            comment.setComment("오히려좋아");

            commentRepository.save(comment);

        }

    }

}

<Test>

init을 통해 comment 객체를 여러개 만들고 setComment를 실행한다.

이후 updateSomething()에 의해 comment가 update되기 때문에

update 쿼리가 잔뜩 실행될 것이다.

    @Test
    void commentTest(){

        commentService.innit();

        //commentRepository.findAll().forEach(System.out::println);

        commentService.updateSomething();
    }

 

이 때 실행된 쿼리를 보면 전체 column에 대한 update가 실행된다.

comment만 업데이트 되는 것이 아니라 다른 column도 update된다.

Hibernate: 
    update
        comment 
    set
        updated_at=?,
        comment=?,
        commented_at=?,
        review_id=? 
    where
        id=?

 

그러면 변동이 없는 column은 update시 제외하도록 할 수 없을까?

 

@DynamicInsert
@DynamicUpdate
public class Comment extends BaseEntity{

@DyncmicUpdate를 사용하자.

 

@DynamicUpdate : 변경된 columns에 대해서만 업데이트 진행. 
@DynamicInsert : insert시 null인 columns 제외

 

실행 결과 변경되지 않은 column이 제외되었다.

Hibernate: 
    update
        comment 
    set
        updated_at=?,
        comment=? 
    where
        id=?

 

이 상태에서 save문을 빼버린다면..?

   @Transactional
    public void updateSomething(){

        List<Comment> comments = commentRepository.findAll();

        for(Comment comment : comments){

            comment.setComment("오히려좋아");

           // commentRepository.save(comment);

        }

    }

그래도 update가 돌아간다.

Hibernate: 
    update
        comment 
    set
        updated_at=?,
        comment=? 
    where
        id=?

 

1. Dirty check : update


영속성 context내에는 dirty check기능이 존재한다.

 

즉, 영속성 관리중에 일어난 변경은 별도의save없어도 DB에 자동으로 영속화 시켜줌.

 

자세히 보기위해 log레벨 수정해주자.

 

<application.yml>

logging:
  level: 
    root: trace

 

@Transactional 범위를 영속성 context가 관리한다. 영속화된 entity는 변경문이 발생하면 save가 없더라고 dirty check에 의해 DB에 영속화하는 query가 동작한다.

 

실제 동작한 쿼리를 보면 dirty check가 진행되고, update query가 실행된 것을 확인할 수 있따.

 

그렇다면 @Transactional을 지워버리고 실행하면? --> dirty check가 존재하지 않는다!!

 

 

 

 2. Dirty Check : Insert


<Comment class> insert에 대한 method도 만들어주자.

  @Transactional
    public void insertSomething(){

        Comment comment = new Comment();

        comment.setComment("뭐하는거냐고지그으으음음");
   }

<Test>

  @Test
    void commentTest(){

        commentService.innit();

        //commentRepository.findAll().forEach(System.out::println);

        commentService.updateSomething();
        
        commentService.insertSomething();
    }

@Transacitonal이 있어도 해당 Comment는 새로 만든 comment이고, 영속화되어있지 않다.

따라서 dirty check가동작하지 않는다.

 

따라서 별도로 영속화 시키기위해 save를 진행해야 한다.

 

그래야 inset query가 실행된다.

    @Transactional
    public void insertSomething(){

        Comment comment = new Comment();

        comment.setComment("뭐하는거냐고지그으으음음");
        
        commentRepository.save(comment);
   }

<Test>

    insert 
    into
        comment
        (created_at, updated_at, comment) 
    values
        (?, ?, ?)

 

 

3. Dirty Check의 성능이슈


 

Dirty check 기능은 save를 하지 않았는데 update를 처리하는 예상하지 못한 동작을 하고.

성능적인 이슈가 발생한다.

 

transaction 내에서 data를 참조하기 위해 select한 entity에 대해서는 dirty checking이 들어간다.

 

data 수가 늘어난다면, dirty checking시간이 증가한다.

 

dirty checking을 하지않고 조회하는 방법이 있나???

 

@ReadOnly = true를 사용하자!

    @Transactional(readOnly = true)
    public void updateSomething(){

@ReanOnly  = true를 적용하면 flush 모드가 manual로 변경된다.

 

쉽게 말하면 flush를 auto로 실행하지 않는다. dirty check가 스킵이 된다.

 

 

조회만 해야하는 로직에서 dirty check를 skip함으로써 성능적 이점을 가져올 수 있다.

 

 

 

4. GitHub : 210711 dirty check


 

bsh6463/BookManager

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

github.com

 

 

'JPA > Trouble shooting' 카테고리의 다른 글

영속성 컨텍스트로 인해 발생하는 issue  (0) 2021.07.11
JPA Fetch type, N + 1 이슈  (0) 2021.07.11
Comments