JPA duplicate key update

1,183 views
Skip to first unread message

A-YUL's Daddy

unread,
Aug 20, 2019, 10:58:12 PM8/20/19
to Korea Spring User Group Q&A
기존 데이터를 update 할 때 save 를 호출하면 

duplicate key 에러가 발생합니다.

mysql/mariadb 에서 제공하는 on duplicate key update 와 같이 

@Id 에 해당하는 값이 있을 때 insert 가 아닌 update 가 수행되도록 처리는 불가능 할까요?

save 할때 마다 findById 해서 있으면 skip 하는 로직을 넣자니... 지저분한것 같고...ㅜㅜ

Jisung Ahn

unread,
Aug 20, 2019, 11:23:19 PM8/20/19
to ks...@googlegroups.com
음.

Session이 끝나면 자동으로 update될겁니다. 
별도로 save를 호출하실 필요가 없습니다. 
Unit of Work 패턴을 참고해보시면 좋을듯 합니다. 



2019. 8. 21. 오전 11:58, A-YUL's Daddy <kim...@gmail.com> 작성:

--
이 메일은 Google 그룹스 'Korea Spring User Group Q&A' 그룹에 가입한 분들에게 전송되는 메시지입니다.
이 그룹에서 탈퇴하고 더 이상 이메일을 받지 않으려면 ksug+uns...@googlegroups.com에 이메일을 보내세요.
웹에서 이 토론을 보려면 https://groups.google.com/d/msgid/ksug/022e0231-7d83-4100-a4fc-faff35d1dbe2%40googlegroups.com을(를) 방문하세요.

jee yong kim

unread,
Aug 21, 2019, 12:21:51 AM8/21/19
to Korea Spring User Group Q&A
narusas 답글 내용을 좀더 첨부해 알려드리면 JPA 에서 get으로 가져온 DTO의 set만으로도 transaction이 끝난 시점에 자동으로 update됩니다. 
만약 new 로 DTO를 생성했다면 명시적으로 save 메소드 이용해야 합니다.

예를 들어 

case 1: new를 이용한 save
Member m = new Member();
m.setId(1)
m.setName("홍길동");
jdbcTemplate.save(m);

case 2: get을 이용해서 가져왔을 경우
Member m = jdbcTemplate.getById(1);
m.setName("홍길동");

case에 따라서 동작하는 방식이 다릅니다.




2019년 8월 21일 수요일 오후 12시 23분 19초 UTC+9, narusas 님의 말:
음.

Session이 끝나면 자동으로 update될겁니다. 
별도로 save를 호출하실 필요가 없습니다. 
Unit of Work 패턴을 참고해보시면 좋을듯 합니다. 

2019. 8. 21. 오전 11:58, A-YUL's Daddy <kim...@gmail.com> 작성:

기존 데이터를 update 할 때 save 를 호출하면 

duplicate key 에러가 발생합니다.

mysql/mariadb 에서 제공하는 on duplicate key update 와 같이 

@Id 에 해당하는 값이 있을 때 insert 가 아닌 update 가 수행되도록 처리는 불가능 할까요?

save 할때 마다 findById 해서 있으면 skip 하는 로직을 넣자니... 지저분한것 같고...ㅜㅜ

--
이 메일은 Google 그룹스 'Korea Spring User Group Q&A' 그룹에 가입한 분들에게 전송되는 메시지입니다.
이 그룹에서 탈퇴하고 더 이상 이메일을 받지 않으려면 ks...@googlegroups.com에 이메일을 보내세요.

김영회

unread,
Aug 21, 2019, 7:25:57 PM8/21/19
to Korea Spring User Group Q&A
@narusas, @jee yong kim

답변 감사합니다.

그럼 '추가' 하는 경우에는 아래와 같이 
@PostMapping(value = "add")
public ResponseEntity<DocLayout> add(@RequestBody DocLayout docLayout) {
 return new ResponseEntity<DocLayout>(layoutService.add(docLayout), HttpStatus.OK); 
}
@Transactional
public DocLayout add(DocLayout layout) {
  layoutRepo.save(layout);
  return layout;
}

'수정' 하는 경우에는 아래와 같은 형태가 되겠네요?
@PostMapping(value = "update")
public ResponseEntity<DocLayout> update(@RequestBody DocLayout docLayout) {
 return new ResponseEntity<DocLayout>(layoutService.update(docLayout), HttpStatus.OK); 
}
@Transactional
public DocLayout add(DocLayout layout) {
  DocLayout docLayout = layoutRepo.findById(layout.getNo());
  docLayout.setA(layout.getA()); 
  docLayout.setB(layout.getB()); 
  return layout;
}

고맙습니다. 

jee yong kim

unread,
Aug 21, 2019, 8:19:49 PM8/21/19
to Korea Spring User Group Q&A
네 맞습니다. 
여기서 좀더 디테일을 살릴려면 null 체크 한번 해주세요

@Transactional
public DocLayout add(DocLayout layout) {
  DocLayout docLayout = layoutRepo.findById(layout.getNo());
   
  if(docLayout!=null){
    docLayout.setA(layout.getA()); 
    docLayout.setB(layout.getB()); 
  }
  return layout;
}

2019년 8월 22일 목요일 오전 8시 25분 57초 UTC+9, 김영회 님의 말:

김영회

unread,
Aug 21, 2019, 8:59:53 PM8/21/19
to Korea Spring User Group Q&A
@jee yong kim

답변 고맙습니다. 

null check 는 하지 않고 service 의 findById 에서 

DocLayout layout = layoutRepo.findById(layoutNo).orElseThrow(() -> new ResourceNotFoundException("DocLayout", "layoutNo", layoutNo));

와 같은 형식으로 update 하기 위한 정보를 찾고 없으면 exception 을 throws 하는 방식으로 하려고 합니다.

좋은 하루 되세요. ^^

2019년 8월 21일 수요일 오전 11시 58분 12초 UTC+9, A-YUL's Daddy 님의 말:
Reply all
Reply to author
Forward
0 new messages