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>=?
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 ์ฟผ๋ฆฌ๊ฐ ๋ฐ์๋ ํ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ด๊ธฐํํด์ค๋ค.
์ ๋ฌธ์ ์ ์ ๋ํ ๋ฐฉ์
- ์์์ฑ ์ปจํ ์คํธ์ ์ํฐํฐ๊ฐ ์๋ ์ํ์์ ๋ฒํฌ ์ฐ์ฐ์ ๋จผ์ ์คํํ๋ค.
- ๋ถ๋์ดํ๊ฒ ์์์ฑ ์ปจํ ์คํธ์ ์ํฐํฐ๊ฐ ์์ผ๋ฉด ๋ฒํฌ ์ฐ์ฐ ์งํ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ด๊ธฐํํ๋ค.