[JPA & Hibernate] Spring Data JPA @Modifying

์›์•Œ๋ ‰์Šคยท2020๋…„ 8์›” 23์ผ
4

JPA

๋ชฉ๋ก ๋ณด๊ธฐ
14/16
post-thumbnail
post-custom-banner

โœ” ๊นƒํ—ˆ๋ธŒ ์†Œ์Šค์ฝ”๋“œ
โœ” Udemy ๊ฐ•์˜์˜์ƒ

๐Ÿš€ @Modifying

@Modifying ์–ด๋…ธํ…Œ์ด์…˜์€ @Query ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์ž‘์„ฑ๋œ ์ˆ˜์ •, ์‚ญ์ œ ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์กฐํšŒ ์ฟผ๋ฆฌ๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋ฐ์ดํ„ฐ์— ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚˜๋Š” INSERT, UPDATE, DELETE ์ฟผ๋ฆฌ์—์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฃผ๋กœ ๋ฒŒํฌ ์—ฐ์‚ฐ ์‹œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

โœ” clearAutomatically

์ด ์†์„ฑ์€ @Modifying ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ ์‹คํ–‰ ์งํ›„, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ Clear ํ•  ๊ฒƒ์ธ์ง€๋ฅผ ์ง€์ •ํ•˜๋Š” ์†์„ฑ์ž…๋‹ˆ๋‹ค. ๋””ํดํŠธ ๊ฐ’์€ false ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ false ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ 1์ฐจ ์บ์‹œ์™€ ๊ด€๋ จ๋œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โœ” ๋ฌธ์ œ์ 

JPA ์—์„œ๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” 1์ฐจ ์บ์‹œ๋ฅผ ํ†ตํ•ด ์—”ํ‹ฐํ‹ฐ๋ฅผ ์บ์‹ฑํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ ‘๊ทผ ํšŸ์ˆ˜๋ฅผ ์ค„์—ฌ์คŒ์œผ๋กœ์จ ์„ฑ๋Šฅ ๊ฐœ์„ ์„ ์ž๋™์œผ๋กœ ํ•ด์ค๋‹ˆ๋‹ค. 1์ฐจ ์บ์‹œ๋Š” @Id ๊ฐ’์„ ํ‚ค๊ฐ’์œผ๋กœ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ findById ๋“ฑ์„ ํ†ตํ•ด์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ–ˆ์„ ์‹œ ID ๊ฐ’์ด 1์ฐจ ์บ์‹œ์— ์กด์žฌํ•œ๋‹ค๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•˜์ง€ ์•Š๊ณ  ์บ์‹ฑ๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ๋ฒŒํฌ ์—ฐ์‚ฐ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๋ฉด ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ• ๊นŒ์š”? ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค - Transient ์ƒํƒœ
  2. save()๋ฅผ ํ†ตํ•ด ์ƒ์„ฑํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค - Persistent ์ƒํƒœ
  3. ๋ฒŒํฌ ์—ฐ์‚ฐ์„ ํ†ตํ•ด ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค - SQL ์‹คํ–‰
    • ๐Ÿ’จ ์ด๋•Œ Flush ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ํ•ด๋‹น ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰ ๋˜๊ธฐ ์ „์˜ ์ฟผ๋ฆฌ๋“ค์€ ๋ชจ๋‘ Flush ๋ฉ๋‹ˆ๋‹ค.
  4. findById() ๋ฅผ ํ†ตํ•ด ์—…๋ฐ์ดํŠธํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.

โœ” ํ…Œ์ŠคํŠธ 1. @Modify

์—”ํ‹ฐํ‹ฐ ์ƒ์„ฑ

@Entity
public class Course {
    
    @Id
    @GeneratedValue
    private Long id;
    
    private String name;
    ...
    
    private Course(String name) {
        this.name = name;
    }
    
    public static Course of(String name) {
        return new Course(name);
    }
}

Repository ์ƒ์„ฑ

@Repository
public interface CourseRepository extends JpaRepository<Course, Long> {
    ...
    
    @Modifying
    @Query(value = "UPDATE Course C SET C.name = ?2 WHERE C.id = ?1"
    int updateById(Long id, String name);
}

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

@Test
@Transactional
public void modifyingTest() {
    Course course = Course.of("before");
    courseRepository.save(course);

    int result = courseRepository.updateById(1L, "after");
    assertEquals(result, 1);

    LOGGER.info(String.format("Updated Course Name -> {%s}", courseRepository.findById(1L).get().getName()));
}

์‹คํ–‰ ๊ฒฐ๊ณผ

๊ฒฐ๊ณผ๋ฅผ ๋ณด์‹œ๋ฉด INSERT, ๊ทธ๋ฆฌ๊ณ  UPDATE ๋ชจ๋‘ ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰ํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ๋„ ์—…๋ฐ์ดํŠธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์— ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ ํ˜„์žฌ 1์ฐจ ์บ์‹œ์— ์บ์‹ฑ์ด ๋˜์—ˆ์œผ๋ฏ€๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  1์ฐจ ์บ์‹œ์—์—์„œ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋งˆ์ง€๋ง‰ ๋กœ๊ทธ๋ฅผ ๋ณด๋ฉด ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์€ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

โœ” ํ…Œ์ŠคํŠธ 2. @Modify(clearAutomatically = true)

๋‹ค์Œ์œผ๋กœ๋Š” clearAutomatically = true ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

@Modifying
@Query(value = "UPDATE Course C SET C.name = ?2 WHERE C.id = ?1"
int updateById(Long id, String name);

๊ฒฐ๊ณผ๋ฅผ ๋ณด์‹œ๋ฉด ์ง€๊ธˆ์€ ์กฐํšŒ๋ฅผ ํ•  ๋•Œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๊ณ  ์—…๋ฐ์ดํŠธ๋œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŽฏ ๊ฒฐ๋ก 

JPA ์˜ 1์ฐจ ์บ์‹œ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ ‘๊ทผ ํšŸ์ˆ˜๋ฅผ ์ค„์—ฌ์„œ ์„ฑ๋Šฅ ๊ฐœ์„ ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ๊ธฐ๋Šฅ์ด์ง€๋งŒ, @Modifying ๊ณผ @Query ๋ฅผ ์‚ฌ์šฉํ•œ ๋ฒŒํฌ ์—ฐ์‚ฐ์—์„œ๋Š” ์ด ๊ธฐ๋Šฅ ๋•Œ๋ฌธ์— ์˜ˆ์ธกํ•˜์ง€ ๋ชปํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์›์ธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

JPA ์—์„œ ์กฐํšŒ๋ฅผ ์‹คํ•ผํ•  ์‹œ์— 1์ฐจ ์บ์‹œ๋ฅผ ํ™•์ธํ•ด์„œ ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ๊ฐ€ 1์ฐจ ์บ์‹œ์— ์กด์žฌํ•œ๋‹ค๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•˜์ง€ ์•Š๊ณ , 1์ฐจ ์บ์‹œ์— ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฒŒํฌ ์—ฐ์‚ฐ์€ 1์ฐจ ์บ์‹œ๋ฅผ ํฌํ•จํ•œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ๋ฐ”๋กœ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜์†์„ ์ปจํ…์ŠคํŠธ๋Š” ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์„ ์•Œ ์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ฆ‰, ๋ฒŒํฌ ์—ฐ์‚ฐ ์‹คํ–‰ ์‹œ 1์ฐจ ์บ์‹œ์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์‹ฑํฌ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š๊ฒŒ ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ @Modifying์˜ clearAutomatically = true๋ฅผ ์„ค์ •ํ•ด์ฃผ๋ฉด ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฒŒํฌ ์—ฐ์‚ฐ ์งํ›„ ์ž๋™์œผ๋กœ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ Clear ํ•ด์ค๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์กฐํšŒ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด 1์ฐจ ์บ์‹œ์— ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“‘ Reference

profile
Alex's Develog ๐Ÿค”
post-custom-banner

0๊ฐœ์˜ ๋Œ“๊ธ€