@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "username", "age"}) //team 은 출력 X!!! 연관 관계에 의한 무한 루프 발생
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
private int age;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
public Member(String userName, int age) {
this.username = userName;
this.age = age;
}
public Member(String userName, int age, Team team) {
this.username = userName;
this.age = age;
if (team != null) {
changeTeam(team);
}
}
//== 연관 관계 편의 메서드 ==//
public void changeTeam(Team team) {
this.team = team;
team.getMemberList().add(this);
}
}
@Modifying
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
@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", 50));
//when
int resultCount = memberRepository.bulkAgePlus(20); //벌크 연산 실행 직전 flush() 자동 호출
Member findMember = memberRepository.findByUsername("member5").orElseGet(() -> null);
System.out.println(findMember);
//then
assertThat(resultCount).isEqualTo(3);
}
memberRepositoy.save
(em.persist)로 영속성 컨텍스트에 member5가 저장
영속성 컨텍스트 | 데이터베이스 | |
---|---|---|
username | member5 | |
age | 50 |
memberRepository.bulkAgePlus(20)
(JPQL) 실행 전 flush() 자동 호출
영속성 컨텍스트 | 데이터베이스 | |
---|---|---|
username | member5 | member5 |
age | 50 | 50 |
memberRepository.bulkAgePlus(20)
실행 후
영속성 컨텍스트 | 데이터베이스 | |
---|---|---|
username | member5 | member5 |
age | 50 | 51 |
memberRepository.findByUsername("member5").orElseGet(() -> null);
데이터 베이스에서 값을 가져오기 때문에 51로 예상하였습니다.
하지만 결과는 50이었습니다.
JPA는 영속성 컨텍스트의 동일성을 보장
하기 때문에 1차 캐시에 있는 값을 반환하게 됩니다. @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", 50));
//when
int resultCount = memberRepository.bulkAgePlus(20); //벌크 연산 실행 직전 flush() 자동 호출
em.clear();
Member findMember = memberRepository.findByUsername("member5").orElseGet(() -> null);
System.out.println(findMember);
//then
assertThat(resultCount).isEqualTo(3);
}
@Modifying(clearAutomatically = true)
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
Member(id=5, username=member5, age=51)