JpqlMain.class
package jpql;
public class JpqlMain {
static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
// 멤버 100명 persist
for (int i = 0; i < 100; i++) {
Member member = new Member("Member" + i, i);
em.persist(member);
}
// 나이가 90이상인 회원의 type을 ADMIN으로 변경하는 쿼리
String query = "update Member m set m.type = jpql.MemberType.ADMIN where m.age >= :age ";
int i = em.createQuery(query).setParameter("age", 90).executeUpdate();
System.out.println(i); // int i는 update된 row의 수
// type이 ADMIN인 member 조회
List<Member> result = em.createQuery("select m from Member m where m.type = jpql.MemberType.ADMIN",Member.class)
.getResultList();
for (Member member : result) {
System.out.println("member = " + member);
}
tx.commit();
} catch (Exception e) {
tx.rollback(); // 오류 발생 시 롤백
e.printStackTrace(); // 에러 내용 출력
} finally {
em.close(); // 종료
}
emf.close();
}
}
결과
Hibernate:
/* select
m
from
Member m
where
m.type = jpql.MemberType.ADMIN */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as team_id5_0_,
member0_.type as type3_0_,
member0_.USERNAME as username4_0_
from
Member member0_
where
member0_.type='ADMIN'
member = Member{id=91, username='Member90', age=90}
member = Member{id=92, username='Member91', age=91}
member = Member{id=93, username='Member92', age=92}
member = Member{id=94, username='Member93', age=93}
member = Member{id=95, username='Member94', age=94}
member = Member{id=96, username='Member95', age=95}
member = Member{id=97, username='Member96', age=96}
member = Member{id=98, username='Member97', age=97}
member = Member{id=99, username='Member98', age=98}
member = Member{id=100, username='Member99', age=99}
벌크 연산을 하게되면 update되는 row의 수가 여러개라도 하나의 update 쿼리문만이 나가서 효율적이다. 위의 예시에서는 100개의 멤버 중 10개의 멤버가 업데이트 되는데 그 과정에서 한개의 update 쿼리만이 나간다.
문제는 벌크 연산은 영속성 컨텍스트는 건들지 않고 DB에 직접 접근하기 때문에 영속성 컨텍스트의 값을 조회하게 되면 원하는 값이 나오지 않을 수 있다.
package jpql;
public class JpqlMain {
static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Member member1 = new Member("회원 1", 20);
Member member2 = new Member("회원 2", 40);
Member member3 = new Member("회원 3", 60);
em.persist(member1);
em.persist(member2);
em.persist(member3);
// 모든 member의 age를 100으로 update
String query = "update Member m set m.age = 100";
int i = em.createQuery(query).executeUpdate(); //executeUpdate()로 벌크 연산, i는 update된 row의 수
Member findMember = em.find(Member.class, member1.getId());
System.out.println("findMember = " + findMember); // 영속성 컨텍스트의 내용이 DB와 다른 값이 출력
// 영속성 컨텍스트 비우기
em.clear();
// 영속성 컨텍스트가 비워져 있으니 DB에 먼저 접근 후 영속성 컨텍스트 초기화
Member findMember2 = em.find(Member.class, member1.getId());
System.out.println("findMember = " + findMember2); // DB와 같은 값이 출력
tx.commit();
} catch (Exception e) {
tx.rollback(); // 오류 발생 시 롤백
e.printStackTrace(); // 에러 내용 출력
} finally {
em.close(); // 종료
}
emf.close();
}
}
출력>>>
Hibernate:
/* update
Member m
set
m.age = 100 */ update
Member
set
age=100
findMember = 20
Hibernate:
select
member0_.id as id1_0_0_,
member0_.age as age2_0_0_,
member0_.TEAM_ID as team_id5_0_0_,
member0_.type as type3_0_0_,
member0_.USERNAME as username4_0_0_
from
Member member0_
where
member0_.id=?
findMember = 100
지금 예시에서는 처음 em.find()로 조회하는 경우 기존 영속성 컨텍스트의 나이가 20인 멤버들이 조회가 되어, DB와는 다른 데이터가 조회된다. 그렇기에 벌크 연산을 사용한 뒤 em.clear()로 영속성 컨텍스트를 비워준다음 다시 DB에 접근해서 내용을 DB에서 영속성 컨텍스트로 가져와야 올바른 값을 조회할 수 있다.
'Spring > JPA' 카테고리의 다른 글
JPA- Open Session In View (0) | 2023.07.16 |
---|---|
JPA- DISTINCT (0) | 2023.07.10 |
JPA-Join Fetch (0) | 2023.06.18 |
JPA- 경로 표현식 (0) | 2023.06.18 |
JPA- 조건식의 사용 (0) | 2023.06.18 |