Spring Data JPA ๊ฒŒ์‹œ๊ธ€์€ ๋Œ€๋ถ€๋ถ„ ์ธํ”„๋Ÿฐ์˜ ๊น€์˜ํ•œ๋‹˜์˜ ๊ฐ•์˜์ธ '์‹ค์ „! ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA' ๊ธฐ๋ฐ˜์œผ๋กœ ๋‚ด์šฉ์„ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฒŒํฌ์„ฑ ์ˆ˜์ • ์ฟผ๋ฆฌ

JPA๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋ณ€๊ฒฝํ•  ๊ฒฝ์šฐ ๋ณ€๊ฒฝ ๊ฐ์ง€ ๊ธฐ๋Šฅ์ด ์ž‘๋™ํ•œ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” ํ•œ ๊ฑด ์”ฉ ์ง€์›๋˜๋Š” ๊ฑฐ๊ณ , ๋ชจ๋“  ๋ฐ์ดํ„ฐ์— ์ผ๊ด„์ ์ธ ์—…๋ฐ์ดํŠธ๋ฅผ ๋‚ ๋ ค์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ(ex ๋ชจ๋“  ์ง์›์˜ ์—ฐ๋ด‰ 10% ์ธ์ƒ)์— ๋ฒŒํฌ์„ฑ ์ˆ˜์ • ์ฟผ๋ฆฌ๋ผ๊ณ  ํ•œ๋‹ค.

์ˆœ์ˆ˜ JPA ์˜ˆ์ œ

  • 20์‚ด์ด๊ฑฐ๋‚˜, 20์‚ด ์ด์ƒ์ธ ํšŒ์›์˜ ๋‚˜์ด๋ฅผ +1
  • MemberJpaRepository.class
public int bulkAgePlus(int age) {
    return em.createQuery("update Member m set m.age = m.age + 1 where m.age >= :age")
            .setParameter("age", age)
            .executeUpdate(); // ์‘๋‹ต ๊ฐ’์˜ ๊ฐœ์ˆ˜ ๋‚˜์˜ด
}
  • MemberJpaRepositoryTest.class
@Test
public void bulkUpdate() {
    //given
    memberJpaRepository.save(new Member("member1", 10));
    memberJpaRepository.save(new Member("member2", 19));
    memberJpaRepository.save(new Member("member3", 20));
    memberJpaRepository.save(new Member("member4", 21));
    memberJpaRepository.save(new Member("member5", 40));

    // when
    int resultCount = memberJpaRepository.bulkAgePlus(20);

    // then
    assertThat(resultCount).isEqualTo(3);
}
update
    member 
set
    age=age+1 
where
    age>=?

img.png|321

DB ํ™•์ธ

Spring Data JPA ์˜ˆ์ œ

Spring Data JPA์—์„œ๋Š” @Modifying ์• ๋…ธํ…Œ์ด์…˜๊ณผ ๋ฐ˜ํ™˜ ๊ฐ’์ด int์ด๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

  • MemberRepository.interface
@Modifying // jpa executeUpdate ๊ฐ™์€ ๊ธฐ๋Šฅ ํ•„์ˆ˜์ž„
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
  • MemberRepositoryTest.class
@Test
public void bulkUpdate() {
    //given
    memberRepository.save(new Member("member1", 10));
    memberRepository.save(new Member("member2", 19));
    memberRepository.save(new Member("member3", 20));
    memberRepository.save(new Member("member4", 21));
    memberRepository.save(new Member("member5", 40));

    // when
    int resultCount = memberRepository.bulkAgePlus(20);

    // then
    assertThat(resultCount).isEqualTo(3);
}
update
    member 
set
    age=age+1 
where
    age>=?

๋ฒŒํฌ์„ฑ ์ˆ˜์ •, ์‚ญ์ œ ์ฟผ๋ฆฌ๋Š” @Modifying ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด org.hibernate.hql.internal.QueryExceptionRequestException: Not supported for DML operations ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๊ผญ ํ•„์ˆ˜๋กœ ๋„ฃ์–ด์ค˜์•ผ ํ•˜๋Š” ์• ๋…ธํ…Œ์ด์…˜์ด๋‹ค.

๋ฒŒํฌ์„ฑ ์ฟผ๋ฆฌ์˜ ์ฃผ์˜ํ•  ์ 

JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—”ํ‹ฐํ‹ฐ๋“ค์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๊ด€๋ฆฌ๊ฐ€ ๋œ๋‹ค. ๋ฒŒํฌ์„ฑ ์ฟผ๋ฆฌ๋Š” ์ด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฌด์‹œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐ’๋“ค๊ณผ DB์— ์žˆ๋Š” ๊ฐ’์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹ค.

  • MemberRepositoryTest.class
@Test
public void bulkUpdate() {
    //given
    memberRepository.save(new Member("member1", 10));
    memberRepository.save(new Member("member2", 19));
    memberRepository.save(new Member("member3", 20));
    memberRepository.save(new Member("member4", 21));
    memberRepository.save(new Member("member5", 40));

    // when
    int resultCount = memberRepository.bulkAgePlus(20);

    List<Member> result = memberRepository.findByUsername("member5");
    Member member = result.get(0);
    System.out.println("member = " + member);

    // then
    assertThat(resultCount).isEqualTo(3);
}
    select
        member0_.member_id as member_i1_0_,
        member0_.age as age2_0_,
        member0_.team_id as team_id4_0_,
        member0_.username as username3_0_ 
    from
        member member0_ 
    where
        member0_.username=?
member = Member(id=5, username=member5, age=40)

์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ถฉ๊ฒฉ์ ์ด๊ฒŒ๋„ member์— ์žˆ๋Š” ๊ฐ’์ด 41์ด ์•„๋‹ˆ๋ผ 40์œผ๋กœ ์ถœ๋ ฅ๋œ๋‹ค. ์ด๋ ‡๊ฒŒ DB์™€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” ๊ฐ’์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ฒŒํฌ ์—ฐ์‚ฐ ํ›„์—๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์•„์˜ˆ ์ดˆ๊ธฐํ™”์‹œ์ผœ์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ DB์˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค.

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋งจ ์œ—์ค„์— EntityManager๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

@PersistenceContext
EntityManager em;
@Test
public void bulkUpdate() {
    //given
    memberRepository.save(new Member("member1", 10));
    memberRepository.save(new Member("member2", 19));
    memberRepository.save(new Member("member3", 20));
    memberRepository.save(new Member("member4", 21));
    memberRepository.save(new Member("member5", 40));

    // when
    int resultCount = memberRepository.bulkAgePlus(20);

 //   em.flush(); // ๋‚จ์•„์žˆ๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๋‚ด์šฉ์„ DB์— ๋ฐ˜์˜. ์—ฌ๊ธฐ์„œ๋Š” ๊ตณ์ด ์•ˆ ํ•ด๋„ ๋œ๋‹ค.
    em.clear(); // ์ดˆ๊ธฐํ™”!

    List<Member> result = memberRepository.findByUsername("member5");
    Member member = result.get(0);
    System.out.println("member = " + member);

    // then
    assertThat(resultCount).isEqualTo(3);
}
    select
        member0_.member_id as member_i1_0_,
        member0_.age as age2_0_,
        member0_.team_id as team_id4_0_,
        member0_.username as username3_0_ 
    from
        member member0_ 
    where
        member0_.username=?
member = Member(id=5, username=member5, age=41)

Spring Data JPA ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™”

Spring Data JPA์—์„œ๋Š” ๊ตณ์ด em.clear() ๋ช…๋ น์„ ์ ์„ ํ•„์š”๊ฐ€ ์—†๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ฃผ์„ ์ฒ˜๋ฆฌ ํ›„ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์ž.

  • MemberRepository.interface
@Modifying(clearAutomatically = true)
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);

@Modifying ์• ๋…ธํ…Œ์ด์…˜์— clearAutomatically ์†์„ฑ์„ true๋กœ(๊ธฐ๋ณธ๊ฐ’์€ false) ์ฃผ๋ฉด ๊ตณ์ด ๋”ฐ๋กœ em.clear()๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ update ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒ๋œ ํ›„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์ค€๋‹ค.

์œ„ ๋ฌธ์ œ์ ์— ๋Œ€ํ•œ ๋ฐฉ์•ˆ

  1. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—†๋Š” ์ƒํƒœ์—์„œ ๋ฒŒํฌ ์—ฐ์‚ฐ์„ ๋จผ์ € ์‹คํ–‰ํ•œ๋‹ค.
  2. ๋ถ€๋“์ดํ•˜๊ฒŒ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๋ฒŒํฌ ์—ฐ์‚ฐ ์งํ›„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.