• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

update시 JPA와 queryDsl방법 질문드립니다

23.02.07 23:25 작성 조회수 4.32k

0


[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/)

[질문 내용]
안녕하세요 JPA강의와 queryDsl 강의를 모두 들으면서 포폴을 만들던 중 궁금한게 생겨 질문드립니다 .

먼저 질문이 많아서 죄송하고 늘 감사드립니다.

 

1.질문

jpa에서 update(변경감지를 사용한 방법 )

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

    team.setTeamName(teamInfoUpdateDto.getTeamName());
    team.setDetailIntro(teamInfoUpdateDto.getDetailIntro());

    return team;
}

2. queryDsl에서 update 방법

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

이 두 방법 다 정상적으로 select 쿼리 이후 update쿼리가 나가는것 까지 확인을 했는데, 차이점이라곤 queryDsl의 리턴 값이 long이다 라는 것밖에 확인을 못했습니다. 둘 중 어떤 것이 update를 할 때 사용하는게 좋을지 모르겠어서 질문드립니다.. 그냥 리턴 차이가 전부인지...

2. 질문

queryDsl에서 update 쿼리의 리턴 값이 long인데 엔티티 타입으로 리턴할 순 없나요??

3. 질문


2번의 문제로 인해
update쿼리의 겨우 update 로직 이후 리턴 타입은 void로 주고 update한 엔티티를 select해서 엔티티 결과값을 리턴 해주었는데 select 쿼리 한 방 추가로 더 나가긴 하는데 이방법이 괜찮은지 다른 방법이 있는지 궁금합니다..

 

감사합니다

답변 2

·

답변을 작성해보세요.

1

chl.cken님의 프로필

chl.cken

질문자

2023.02.09

서포터즈 y2gcoder님 닉넴이 바뀌셨네요??ㅎㅎㅎ

늘 답변 달아주셔서 감사합니다!
덕분에 혼자 궁금했던 부분들이 많이 해결되었습니다.

감사합니다!!

0

y2gcoder님의 프로필

y2gcoder

2023.02.08

안녕하세요, chl.cken 님. 공식 서포터즈 y2gcoder 입니다.

  1. 개인적으로는 JPA 스럽게 사용하는 방법은 더티체킹을 이용하는 방법이라고 생각합니다. 더티체킹을 이용하지 못하는 상황이 아니라면 저는 1번 방법을 선택할 것 같습니다. 또한 더티체킹을 이용할 때는 트랜잭션 커밋 시점에 스냅샷 비교를 통한 update 쿼리가 만들어져 쓰기 지연 SQL 저장소에 있던 다른 쿼리들과 같이 DB로 전송되기 때문에, 좀 더 성능 향상에 이점이 있을 것이라 생각합니다. 또한 지금 사용하고 계신 QueryDSL의 update는 벌크 연산용으로 영속성 컨텍스트에 반영되지 않는 문제점도 있어 후속 처리가 필요할 수도 있기 때문에 1번 방법으로 사용할 것 같습니다.

  2. 이것에 관해서는 자세히는 모르겠으나, JDBC 드라이버를 이용한 쿼리문이나 JdbcTemplate를 사용한 경험을 토대로 생각해봤을 때, update query 문을 만들어 DB로 보낼 때, 응답값으로 해당 쿼리로 수정된 row 수가 반환되었습니다. 그러한 점에서 착안해봤을 때, QueryDSL의 update()의 결과를 바로 엔티티로 받는 것은 어렵지 않을까 생각합니다.

  3. 현재 개발하고 계신 프로젝트의 요구사항이 어떤 지 자세히 모르는 상황에서 조심스럽게 답변을 드려보겠습니다. 만약 요구사항 중 수정한 내용이 반영된 엔티티를 반환해야 한다면 JPA의 더티체킹으로 해주는 것이 맞다고 생각합니다. 혹은 다량의 데이터를 수정하고 반환해야 한다면 QueryDSL의 update()를 이용해 벌크연산을 해준 뒤, 다시 조회해오는 것이 맞다고 생각합니다.

 



감사합니다.

chl.cken님의 프로필

chl.cken

질문자

2023.02.15

y2gcoder 서포터즈님 먼저 답글 감사합니다!! 고민 됐던 것들이 많이 해결되었습니다.
(아고..제가 위에 달았는데 여기 또 있는지 몰랐네요! )

제가 질문을 드리고 나서 더티체킹에 대한 궁금증이 가시지 않아서 2차 질문을 드려요 ㅠㅠ

바쁘신데 죄송합니다.. 도저히 모르겠어서..

 

프론트와 백앤드가 API 통신한다고 가정하에..질문드려봅니다.

"수정"할 때 더티체킹 방식을 활용하는 것이 얻는 이점들은 이해했습니다

  • 트랜잭션 커밋 시점에 스냅샷 비교를 통한 update 쿼리가 만들어져 쓰기 지연 SQL 저장소에 있던 다른 쿼리들과 같이 DB로 전송되기 때문에, 성능 향상

  • 모든 값들이 채워지지 않았을 경우 Null 값으로 치환되지 않음 (더티체킹이 아닐 경우 빈값은 null로 변경됨)

 

 

그래서 저도 현재 만들고 있는 수정 API 부분에선 더티체킹을 사용하려고 하는데요

  1. 웬만하면 @Setter 사용을 지양하라 라는 말씀에 기반하여 @Builder 패턴을 사용하여

    setter사용을 줄이고 싶은데요 아래의 예제의 경우는 일부긴 하지만...어떤 느낌으로 Builder를 사용하여 적용할 수 있나요...?? 수정을 진행할 땐 Setter 말고 다른 방법으로 하는 법을 도저히 모르겠습니다..ㅠㅠ ( @Builder 패턴 사용법은 익히 알고 있으나.. 해당 서비스 로직에서 적용법을 모르겠네요 ㅠㅠ)

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

    team.setTeamName(teamInfoUpdateDto.getTeamName());
    team.setDetailIntro(teamInfoUpdateDto.getDetailIntro());

    return team;
}
  1. 위의 예제는 teamId를 알 수 있어서 더티체킹이 가능한데 수정할 Id를 모를 경우는 어떻게 더티체킹을 이용할 수 있나요...?? 이 경우는queryDsl로 처리했는데 빈 값일 경우 null로 바껴버리네요...

  • 이럴 경우 프론트에서 get API로 먼저 게시판 상세 데이터를 가져온 다음 -> 프론트에서 값을 보낼때 "수정할 부분은 수정된 내용 반영하고, null이 없는 get 한 데이터"를 보내는 방법 밖에 없나요?

  • 만약 teamId는 전달되지 않았고, memberId, boardId만 전달된다면 queryDsl에서 해당 게시글의, 해당 작성자를 찾아서 teamId를 리턴하는 로직을 추가한 다음 더티체킹 방법을 이용해야할까요?)

    이상 추가 질문드립니다!!
    감사합니다

     

     

y2gcoder님의 프로필

y2gcoder

2023.02.15

먼저 좋은 질문 주셔서 감사합니다!

 

  1. setter 사용을 지양하라는 말이 변경하는 메서드를 추가하지 말라는 뜻은 아닙니다! setter를 무분별하게 사용했을 때의 문제점은

    1) 변경이 무분별하게 일어날 가능성이 많다.
    2) 변경 의도를 짐작하기 어렵다.

    정도로 저는 생각합니다. 하지만 저희는 엔티티의 상태를 변경해야 하기 때문에 변경 의도를 나타내는 메서드를 만들어야 합니다. 위에 말씀해주신 예시에서 간단하게 생각해본 바로는 changeTeamName(), changeDetailIntro() 정도로 네이밍을 생각해볼 수 있을 것 같습니다. 엔티티에서 상태를 변경하는 메서드는 만들어도 됩니다!

  2. 사실 엔티티의 식별자를 모르고 엔티티를 수정한다는 말씀이 잘 이해가 되지 않습니다. 제가 요구사항을 모르는 상태로 답변드리는 것이라 원하시는 답변이 나오지 않을 수도 있을 것 같습니다. 다만 개인적으로 엔티티는 식별자를 통해 엔티티를 조회하는 것이 기본이고 혹은 해당 엔티티의 유니크한 값을 조건으로 조회해오는 것을 기본으로 생각하고 있습니다.

    team과 member가 연관이 있고, member와 게시글이 연관이 있다고 가정하고 말씀드리면,

    1) 게시글 상세 데이터에서 연관 member 데이터를 불러올 때 team 식별자를 같이 보낸다.
    2) 게시글 수정 요청에서 받은 member에서 team 식별자를 가져와 조회한다.

    정도로 생각이 납니다.

많은 도움이 되지 못한 것 같아 죄송합니다.

chl.cken님의 프로필

chl.cken

질문자

2023.02.16

서포터즈님 답변 감사합니다!!

  1. 내용에대해 확실히 이해했습니다!

  2. 2번 답변의 경우 식별자를 통해 엔티티를 조회하는 것이 기본이고 혹은 해당 엔티티의 유니크한 값을 조건으로 조회해온다는 걸 통해 2가지 엔티티를 가져와서 setter로 더티체킹 적용했습니다 ^^


    감사합니다 ^^

 

y2gcoder님의 프로필

y2gcoder

2023.02.16

멋집니다 ㅎㅎ
파이팅입니다!