Home > Troubleshooting > πŸ”[Troubleshooting] πŸš€ PUT, PATCH, JPA λ³€κ²½ 감지

πŸ”[Troubleshooting] πŸš€ PUT, PATCH, JPA λ³€κ²½ 감지
Troubleshooting Backend Development Spring Boot

πŸš€ PUT, PATCH, JPA λ³€κ²½ 감지!

βœ… 잘 κ΅¬ν˜„λœ λΆ€λΆ„

1. λͺ…ν™•ν•œ 계측 ꡬ쑰

  • Controller: HTTP μš”μ²­ 처리
  • Service: λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μˆ˜ν–‰
  • Repository: 데이터 μ ‘κ·Ό
  • Entity: 자체 μƒνƒœ 관리 (updateStudentName)

각 κ³„μΈ΅μ˜ μ±…μž„μ΄ λͺ…ν™•ν•˜κ²Œ λΆ„λ¦¬λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

2. μ μ ˆν•œ μ˜ˆμ™Έ 처리

studentRepository.findByStudentId(studentId)
    .orElseThrow(() -> new IllegalArgumentException("μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” ν•™μƒμž…λ‹ˆλ‹€."));

μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” λ¦¬μ†ŒμŠ€μ— λŒ€ν•œ μˆ˜μ •μ„ 사전에 λ°©μ§€ν•©λ‹ˆλ‹€.

3. 직관적인 λ©”μ„œλ“œ λͺ…λͺ…

changeStudentName처럼 κΈ°λŠ₯을 λͺ…ν™•ν•˜κ²Œ ν‘œν˜„ν•˜λŠ” λ©”μ„œλ“œλͺ…을 μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.


πŸ”§ κ°œμ„  μ œμ•ˆ

μ œμ•ˆ 1: HTTP λ©”μ„œλ“œ λ³€κ²½ (PUT β†’ PATCH)

πŸ“Œ 문제점

ν˜„μž¬ @PutMapping을 μ‚¬μš© μ€‘μž…λ‹ˆλ‹€. REST 섀계 μ›μΉ™μ—μ„œ:

  • PUT: λ¦¬μ†ŒμŠ€ 전체λ₯Ό ꡐ체 (λͺ¨λ“  ν•„λ“œ ν•„μš”)
  • PATCH: λ¦¬μ†ŒμŠ€ μΌλΆ€λ§Œ μˆ˜μ • (λ³€κ²½ν•  ν•„λ“œλ§Œ)

ν˜„μž¬ κ΅¬ν˜„μ€ β€˜μ΄λ¦„β€™ ν•„λ“œλ§Œ μˆ˜μ •ν•˜λ―€λ‘œ λΆ€λΆ„ μˆ˜μ •μ— ν•΄λ‹Ήν•©λ‹ˆλ‹€.

✨ κ°œμ„  μ½”λ“œ

Before (ν˜„μž¬)

@PutMapping("/change/student/name/{studentId}")
public ResponseEntity<StudentResponseDto> changeStudentName(
    @PathVariable String studentId,
    @RequestBody StudentRequestDto requestDto
) {
    return ResponseEntity.ok(studentService.updateStudentName(studentId, requestDto));
}

After (κ°œμ„ )

import org.springframework.web.bind.annotation.PatchMapping;

@PatchMapping("/change/student/name/{studentId}")
public ResponseEntity<StudentResponseDto> changeStudentName(
    @PathVariable String studentId,
    @RequestBody StudentRequestDto requestDto
) {
    return ResponseEntity.ok(studentService.updateStudentName(studentId, requestDto));
}

μ œμ•ˆ 2: JPA λ³€κ²½ 감지(Dirty Checking) ν™œμš©

πŸ“Œ 문제점

@Transactional λ©”μ„œλ“œ λ‚΄μ—μ„œ λΆˆν•„μš”ν•œ save() 호좜이 μžˆμŠ΅λ‹ˆλ‹€.

πŸ’‘ 핡심 κ°œλ…

JPAλŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ κ΄€λ¦¬λ˜λŠ” μ—”ν‹°ν‹°μ˜ 변경을 μžλ™μœΌλ‘œ κ°μ§€ν•©λ‹ˆλ‹€.
νŠΈλžœμž­μ…˜μ΄ 컀밋될 λ•Œ λ³€κ²½λœ λ‚΄μš©μ΄ μžλ™μœΌλ‘œ DB에 λ°˜μ˜λ©λ‹ˆλ‹€.

✨ κ°œμ„  μ½”λ“œ

Before (ν˜„μž¬)

@Transactional
public StudentResponseDto updateStudentName(String studentId, StudentRequestDto requestDto) {
    Student findStudent = studentRepository.findByStudentId(studentId)
        .orElseThrow(() -> new IllegalArgumentException("μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” ν•™μƒμž…λ‹ˆλ‹€."));

    findStudent.updateStudentName(requestDto.getName());

    // λΆˆν•„μš”ν•œ save 호좜
    Student savedStudent = studentRepository.save(findStudent);

    return StudentResponseDto.fromEntity(savedStudent);
}

After (κ°œμ„ )

@Transactional
public StudentResponseDto updateStudentName(String studentId, StudentRequestDto requestDto) {
    // 1. μ—”ν‹°ν‹° 쑰회 β†’ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ 관리 μ‹œμž‘
    Student findStudent = studentRepository.findByStudentId(studentId)
        .orElseThrow(() -> new IllegalArgumentException("μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” ν•™μƒμž…λ‹ˆλ‹€."));

    // 2. μ—”ν‹°ν‹° μƒνƒœ λ³€κ²½
    findStudent.updateStudentName(requestDto.getName());

    // 3. save() 없이도 νŠΈλžœμž­μ…˜ 컀밋 μ‹œ μžλ™μœΌλ‘œ UPDATE 쿼리 μ‹€ν–‰
    return StudentResponseDto.fromEntity(findStudent);
}

πŸ“Š κ°œμ„  효과

  • μ½”λ“œ κ°„κ²°μ„± ν–₯상
  • JPA의 λ³€κ²½ 감지 λ©”μ»€λ‹ˆμ¦˜ ν™œμš©
  • λΆˆν•„μš”ν•œ λ©”μ„œλ“œ 호좜 제거

πŸ“ μš”μ•½

ν•­λͺ© ν˜„μž¬ κ°œμ„  ν›„
HTTP λ©”μ„œλ“œ @PutMapping @PatchMapping
Repository 호좜 save() λͺ…μ‹œμ  호좜 λ³€κ²½ κ°μ§€λ‘œ μžλ™ μ €μž₯
RESTful 섀계 λΆ€λΆ„μ μœΌλ‘œ μ€€μˆ˜ μ™„μ „νžˆ μ€€μˆ˜