기존에 프로젝트에서는 변경감지를 쓸 일이 없었는데..
가령 조회수같은것을 업데이트 쳐준다거나..? 그런것을 사용하는것이 공교롭게도 없었다.
그런데 이번에 새로운 프로젝트에서 변경감지를 쓸 일이 발생하였고 몇번을 헤맨끝에 성공!
그래서 간단하게 변경감지의 개념과 왜 헤맸는지 기록하고자 한다.
변경감지란?
객체나 DTO에 새로운값을 setter로 저장하면 트랜잭션 커밋시점에 jpa에서 알아서 그 변경된값으로 update쿼리를 생성해서 update 쿼리를 날려주도록 시킨다.
이는 반드시 영속성 엔티티로 존재할때만 가능하다.
service, repository에서 쿼리를 날렸을경우(save, find, select...)
엔티티는 영속상태로 바뀌게 된다. 이것을 영속성 엔티티라고 한다.
JPA 에 존재하는 엔티티 매니저를 통해 쿼리문을 날리면 자동으로 해당 엔티티는
영속성 컨텍스트에 들어가서 트랜잭션이 끝나는 시점까지 따로 관리하게 된다.
헤맨이유
적용과정으로 똑같이했는데도..적용이 안되가지구 계속 헤맸다.
근데 원인은 트랜잭션!!!!!
게시글 조회할때 트랜잭션을 설정하지 않아서 발생하였다.
기존에 새로 만들던 프로젝트라 클래스파일 상단에 트랜잭션 어노테이션이 붙어있지 않았다.
그래서 게시글 조회 메소드에 트랜잭션 처리를 해주고 적용하였더니, 정상적으로 조회수가 증가하였다.
변경감지를 사용하려면 객체가 영속성 엔티티로 존재해야만 가능한데, 그 중요한걸 빠뜨리고 있었..
주의사항
반면에 병합(merge)을 사용할경우 영속성 엔티티로 존재하지 않아도 update문을 날려준다.(없으면 값을 persist를 사용하여 새로 등록한다.)그리고 엔티티의 모든값을 setting해줘야하며, 모든 값을 setting하지 않을경우 setting해주지 않는 값은 모두 null로 들어가니 주의. 되도록이면 사용하지 않는게 좋다.
적용과정
ex) 게시판의 게시글 조회수 증가
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);
}