📌 Named 쿼리 - 정적 쿼리
- 미리 정의해서 이름을 부여해두고 사용하는 JPQL
- 자주 사용되는 쿼리를 표준화하고, 코드의 가독성과 유지보수성을 높이기 위한 방법
- 정적 쿼리
- 어노테이션, XML에 정의
- 애플리케이션 로딩 시점에 초기화 후 재사용🌟
- 쿼리가 실행될 때마다 컴파일되는 동적 쿼리와 다름!!!!
- 애플리케이션 로딩 시점에 쿼리를 검증🌟🌟
- 문법 오류를 사전에 발견할 수 있음
//Member 엔터티 클래스에 @NamedQuery 어노테이션을 사용하여 쿼리를 정의
@Entity
@NamedQuery(
name = "Member.findByUsername",
query="select m from Member m where m.username = :username")
public class Member {
...
}
// 쿼리를 실행할 때 createNamedQuery 메서드를 통해 호출
List<Member> resultList =
em.createNamedQuery("Member.findByUsername", Member.class)
.setParameter("username", "회원1")
.getResultList();
Spring Data JPA에서는?! (이름없는 Named Query라고 부름?)
⇒ 인터페이스 메서드 위에 바로 선언
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from U/ser u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}
- JPA가 @Query("select u from U/ser u where u.emailAddress = ?1" 이를 Named Query로 등록한다고 보면 됨 (?)
- Named 쿼리는 엔티티 클래스 또는 XML 파일에 정의되어 여러 리포지토리에서 재사용할 수 있는 반면, @Query는 특정 메서드에 대해 정의되며 재사용이 불가능
- 애플리케이션 로딩 시점에 이를 파싱함 ⇒ 문법 오류를 다 잡아줌
실무에서는 Spring Data JPA를 섞어 사용하는 것이 좋음 🌟
📌 JPQL - 벌크 연산
- 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면?
- JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL 실행
- 재고가 10개 미만인 상품을 리스트로 조회한다.
- 상품 엔티티의 가격을 10% 증가한다.
- 트랜잭션 커밋 시점에 변경감지가 동작한다.
- 변경된 데이터가 100건이라면 100번의 UPDATE SQL 실행
📌 벌크 연산 예제
- 쿼리 한 번으로 여러 테이블 로우 변경(엔티티)
int resultCount = em.createQuery("update Member m set m.age = 20")
.executeUpdate(); //영향받은 엔티티 수 반환 => 3
System.out.println("resultCount = " + resultCount);
>> 모든 회원의 나이가 20살로 변경됨
- executeUpdate()의 결과는 영향받은 엔티티 수 반환
- UPDATE, DELETE 지원
- INSERT(insert into .. select, 하이버네이트 지원)
🚨 벌크 연산 주의 🚨
- 벌크 연산은 영속성 컨텍스트를 무시하고 데이터베이스에 직접 쿼리
<해결책 2가지 (연속된 해결책 아님)>
- 벌크 연산을 먼저 실행
- 이러면 영속성 컨텍스트에 아무것도 없으니 O
- 벌크 연산 수행 후 영속성 컨텍스트 초기화
Member member1 = new Member();
member1.setUser("회원1");
member.setTeam(teamA);
em.persist(member1);
Member member2 = new Member();
member2.setUser("회원2");
member.setTeam(teamA);
em.persist(member2);
Member member3 = new Member();
member3.setUser("회원3");
member.setTeam(teamB);
em.persist(member3);
//지금 member1,2,3가 영속성 컨텍스에 들어있음
//벌크 연산으로 DB를 강제로 업데이트함 => 영속성 컨텍스트에 반영 안되어있음
//DB에는
//Flush
int resultCount = em.createQuery("update Member m set m.age = 20")
.executeUpdate(); //영향받은 엔티티 수 반환 => 3
System.out.println("resultCount = " + resultCount);
System.out.println("member1.getAge() = " + member1.getAge());
System.out.println("member2.getAge() = " + member2.getAge());
System.out.println("member3.getAge() = " + member3.getAge());
>> DB에만 반영이 되어있는 것.
int resultCount = em.createQuery("update Member m set m.age = 20")
.executeUpdate(); //영향받은 엔티티 수 반환 => 3
em.clear();
Member findMember = em.find(Member.class, member1.getId());
- em.clear() 후 em.find를 하면 영속성 컨텍스트가 초기화된 상태에서 다시 조회하므로 20살로 조회가 됨
반응형
'Study > JPA' 카테고리의 다른 글
객체지향 쿼리 언어) JPQL - 페치 조인(fetch join) (0) | 2024.07.30 |
---|---|
객체지향 쿼리 언어) JPQL - 경로 표현식 (0) | 2024.07.30 |
JPQL (0) | 2024.07.27 |
조인과 서브쿼리 (0) | 2024.07.27 |
프로젝션과 페이징 (0) | 2024.07.27 |