[JPA] 변경감지(Dirty Checking)

doyeon kim·2022년 8월 8일
0

기존에 프로젝트에서는 변경감지를 쓸 일이 없었는데..
가령 조회수같은것을 업데이트 쳐준다거나..? 그런것을 사용하는것이 공교롭게도 없었다.
그런데 이번에 새로운 프로젝트에서 변경감지를 쓸 일이 발생하였고 몇번을 헤맨끝에 성공!

그래서 간단하게 변경감지의 개념과 왜 헤맸는지 기록하고자 한다.



변경감지란?

객체나 DTO에 새로운값을 setter로 저장하면 트랜잭션 커밋시점에 jpa에서 알아서 그 변경된값으로 update쿼리를 생성해서 update 쿼리를 날려주도록 시킨다.
이는 반드시 영속성 엔티티로 존재할때만 가능하다.

여기서 영속성 엔티티란?

service, repository에서 쿼리를 날렸을경우(save, find, select...)
엔티티는 영속상태로 바뀌게 된다. 이것을 영속성 엔티티라고 한다.

영속성 컨텍스트란?

JPA 에 존재하는 엔티티 매니저를 통해 쿼리문을 날리면 자동으로 해당 엔티티는
영속성 컨텍스트에 들어가서 트랜잭션이 끝나는 시점까지 따로 관리하게 된다.


setter로 값을 새로 저장하게되면, 새로 commit쿼리가 생성되는게 아니라 영속성 컨텍스트안에서 현재 찾아진 값과 setter값을 대조하여서, 값이 변경되었을경우 변경된 값으로 자동으로 update쿼리를 날려준다.

헤맨이유

적용과정으로 똑같이했는데도..적용이 안되가지구 계속 헤맸다.
근데 원인은 트랜잭션!!!!!
게시글 조회할때 트랜잭션을 설정하지 않아서 발생하였다.
기존에 새로 만들던 프로젝트라 클래스파일 상단에 트랜잭션 어노테이션이 붙어있지 않았다.
그래서 게시글 조회 메소드에 트랜잭션 처리를 해주고 적용하였더니, 정상적으로 조회수가 증가하였다.
변경감지를 사용하려면 객체가 영속성 엔티티로 존재해야만 가능한데, 그 중요한걸 빠뜨리고 있었..



주의사항

반면에 병합(merge)을 사용할경우 영속성 엔티티로 존재하지 않아도 update문을 날려준다.(없으면 값을 persist를 사용하여 새로 등록한다.)그리고 엔티티의 모든값을 setting해줘야하며, 모든 값을 setting하지 않을경우 setting해주지 않는 값은 모두 null로 들어가니 주의. 되도록이면 사용하지 않는게 좋다.



적용과정

ex) 게시판의 게시글 조회수 증가

  1. 변경감지를 적용하고자 엔티티에 조회수 증가 메소드 생성
  2. 서비스단에 조회수 증가 로직을 새로생성
  3. 서비스단에서 게시글 조회 로직을 탔을때 만들어둔 2,1을 순서대로 적용시키기
  1. 조회수 증가 메소드
    open fun addViews(views: Int) {
      this.views = views + 1;
    }

2. 조회수 증가

private void updateViews(Long id, int views) {
        Board board = searchBoardService.getBoard(id).orElseThrow(() -> new NoSuchElementException());
        board.addViews(views);
    }
    
    
    
3. 게시글 조회

public BoardResponseDto getBoard(Long id) {
        Board board = searchBoardService.getBoard(id).orElseThrow(() 
        									-> new NoSuchElementException());
        //조회수 증가
        updateViews(board.getId(), board.getViews());
        return new BoardResponseDto(board);
    }


profile
아직은 개발이 재밌음

0개의 댓글