벌크성 업데이트 또는 삭제(Bulk Update/Delete)는 데이터베이스에서 한 번에 여러 행을 업데이트하거나 삭제하는 작업을 의미합니다.
개별적으로 업데이트 또는 삭제 쿼리를 실행하는 것보다 효율적으로 작업을 수행할 수 있습니다. 예를 들어, 특정 조건을 만족하는 모든 행의 값을 일괄적으로 변경하거나 삭제할 수 있습니다.
@Repository
public class MemberJpaRepository{
@PersistenceContext // entitymanager 주입하는 어노테이션
EntityManager em; // 영속성 컨텍스트로 데이터를 관리함
// 순수 jpa 는 @Modifying(clearAutomatically = true)를 사용하지 않고 Entity Manager를 활용하여 데이터베이스 직접 변경 작업을 수행한다.
public int bulkUpdate(int age){
int resultCount = em.createQuery("update Member m set m.age = m.age+1 where m.age = :age")
.setParameter("age",age)
.executeUpdate(); // JPA 메소드 중 하나로 , 영속성 컨텍스트를 우회하여 직접 데이터베이스에 대한 업데이트를 실행(쿼리 전달)하고, 업데이트 실행에 성공한 행의 수를 반환한다.
// 그렇기 때문에 데이터베이스와 영속성 컨텍스트의 값이 일치 하지 않을 수 있다.
em.clear(); // 벌크성 업데이트 후 초기화하여 영속성 컨텍스트와 동기화 시킴
return resultCount;
}
}
@Modifying(clearAutomatically = true)
@Query("update Member m set m.age = m.age+1 where m.age >=20")
int bulkUpdate(@Param("age")int age);
@Modifying 애노테이션은
bulkUpdate() 메소드가 데이터베이스를 수정하는 작업을 수행한다는 것을 나타냅니다. 이 애노테이션을 사용하여 Spring Data JPA는 해당 메소드를 실행할 때 트랜잭션을 시작하고, 변경 작업이 완료되면 트랜잭션을 커밋합니다.
벌크성 수정, 삭제 쿼리는 @Modifying 어노테이션을 사용 사용하지 않으면 다음
org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for
DML operations
예외 발생
@Modifying(clearAutomatically = true) (이 옵션의 기본값은 false )
이 옵션 없이 회원을 findById로 다시 조회하면 영속성 컨텍스트에 과거 값이 남아서 문제가 될 수 있다.
⭐️ 참고: 벌크 연산은 영속성 컨텍스트를 무시하고 실행하기 때문에, 영속성 컨텍스트에 있는 엔티티의 상태와 DB에 엔티티 상태가 달라질 수 있다.
권장하는 방안
1. 영속성 컨텍스트에 엔티티가 없는 상태에서 벌크 연산을 먼저 실행한다.
2. 부득이하게 영속성 컨텍스트에 엔티티가 있으면 벌크 연산 직후 영속성 컨텍스트를 초기화 한다.
참고 : 김영한 강의 Spring Data Jpa