포스트

update

Update

  • JPA에는 수정과 관련된 메서드가 없다
  • 그렇다면 어떻게 해야하는 것일까??
  • 방법은 두가지가 있다.
  • 1) 더티체킹(변경감지)
  • 2) 벌크연산

더티체킹(변경감지)

  • Entity를 조회하여 조회된 Entity 데이터를 변경만 하면 DB에 자동으로 반영이 되도록 한 것이다.
  • JAP는 영속성 콘텍스트를 생성하여 DB와 유사하게 Entity의 Life Cycle을 관리한다.
  • JAP는 영속성 콘텍스트에 Entity를 보관할 때 상태를 저장한다. 이를 스탭샷이라고 한다
  • 영속성 콘텍스트가 flush(영속성 콘텍스트의 변경 내용을 DB에 반영하는 것)되는 시점에 스냅샷과 현재 Entity의 상태를 비교한다
  • 이후 변경된 필드들을 이용하여 쓰기 지연 SQL 저장소에 Update 쿼리를 생성하여 쌓아둔다
  • 모든 작업이 끝나고 트랜잭션을 커밋으로 처리할 때, 쓰기 지연 SQL 저장소에 있는 쿼리들을 DB에 전달하여 Update한다
  • 이것은 Service Layer에서 진행한다

벌크연산(Querydsl)

  • Repository 단에서 시행한다.
  • 수정할 데이터를 update 퀄에서 선언한다.
  • .set을 이용하여 Dto로 전달받은 값을 꺼낸다
  • .where 절을 이용하여 조건을 건다(선택)
  • QueryDsl로 해당 쿼리를 날리고 update한 다음 select 해보면 수정된 값이 반영되지 않는다.
  • 이유는 영속성 컨텍스트에 값이 남아있기 때문이다
  • 이때는 EntityManager를 추가해주고
  • em.clear(); 와 em.flush(); 를 해주어야 한다
  • 벌크연산의 경우 리턴 값을 숫자만 리턴할 수 있다
  • 따라서 조회 쿼리를 한 번 더 만들어야 한다
  • 지정되지 않은 값들은 null로 들어가게 된다.

JPA와 Querydsl의 차이점

  • JPA스럽게 사용하는 방법은 더티체킹이라고 한다
  • JAP(더티체킹) 특징
    • 트랜잭션 커밋 시점에 스냅샷 비교를 통한 update 쿼리가 만들어진다
    • 쓰기 지연 SQL 저장소에 있던 다른 쿼리들과 같이 DB로 전송된다. 이는 성능을 향상시킨다
    • DB에 존재하는 모든 값들이 채워지지 않아도 null로 치환되지 않는다
  • Querydsl(벌크연산) 특징
    • Querydsl의 update는 벌크 연산용으로 영속선 컨텍스트에 반영되지 않는 문제점
    • 혹은 다량의 데이터를 수정하고 반환해야 할 경우 사용한다
    • DB에 존재하는 모든 값들이 채워지지 않으면 null로 치환된다
    • 후속 처리가 필요할 수 있다(추가적인 조회 쿼리)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// JAP 더티체킹 (Service Layer)
@RequiredArgsConstructor
@Transactional
public class BoardService{
  private final EntityManager em;  

  public Team updateTeamInfo(TeamInfoUpdateDto teamInfoUpdateDto){
    Team team = em.find(Team.class, teamInfoUpdateDto.getTeamId());

    team.setTeamName(teamInfoUpdateDto.getChangeTeamName());
    team.setDetailIntro(teamInfoUpdate.getChangeDetailIntro());

    return team;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Querydsal(벌크연산) (Repository Layer)

@RequiredArgsConstructor
public class BoardRepository{

  private final EntityManager em;

  public long updateTeamInfo(TeamInfoUpdateDto teamInfoUpdateDto){
    return queryFactory
          .update(team)
          .set(team.teamName, teamInfoUpdateDto.getTeamName())
          .where(team.id.eq(teamInfoUpdateDto.getTeamId()))
          .execute();
    
    em.clear();
    em.flush();
  }
}