728x90
EntityManager 를 쓰레드간 공유하면 안되는 이유
EntityManager 를 쓰레드간 공유하면 안되는 이유에 대해서 배워보자.
Test
테스트할 주제는 EntityManager 를 하나로 사용하고 있는 상태에서 서로 다른 Thread 두 개를 생성하고 ThreadA 는 데이터베이스에서 데이터를 읽어와 1차 캐시에 저장하는 역할을 하고, ThreadB 에서는 데이터 조회와, 데이터 수정 작업을 담당하게끔 코드를 짜서 테스트할 것이다.
포인트는 ThreadB 에서 데이터를 읽어올 때, 1차 캐시에 존재하는 데이터를 읽어올지, 데이터베이스로부터 값을 조회해올지가 포인트다.
@DisplayName("1차 캐시 테스트")
@SpringBootTest
class FirstCacheTest {
@Value("${persistence.unitname}")
private String persistenceUnitName;
@DisplayName("EntityManger 를 스레드간 공유하면 1차 캐시의 내용을 공유하는지 테스트")
@Test
void oneEntityManagerAndTwoThreadIsSharedFirstCache() throws Exception {
// given
EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);
insertDummyData(emf);
// when
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
/*
* 서로 다른 스레드 두개 생성 : 클라이언트의 요청이 두 개 들어왔다고 가정
* threadA -> threadB 순서로 한다고 가정
*/
tx.begin();
Thread threadA = new Thread(() -> {
// 데이터베이스에서 조회하여 1차 캐시에 내용 저장
Member member = em.find(Member.class, 1L);
});
Thread threadB = new Thread(() -> {
// 여기서 1차 캐시에서 조회되는지 데이터베이스에서 조회되는지 확인
Member member = em.find(Member.class, 1L);
member.setAge(29);
em.persist(member);
});
// 2초 뒤에 스레드 B 시작
threadA.start();
Thread.sleep(2000);
threadB.start();
// 3초 뒤에 커밋하고 종료
Thread.sleep(3000);
tx.commit();
em.close();
emf.close();
}
@DisplayName("더미 데이터 삽입")
private void insertDummyData(EntityManagerFactory emf) {
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Member member = new Member();
member.setUsername("JungHo");
member.setAge(28);
em.persist(member);
tx.commit();
em.close();
}
}
테스트 결과 ThreadA 는 예상하는 것처럼 동작하고, ThreadB 에서 같은 EntityManager 를 사용하고 있어서, ThreadA 에서 읽기 처리 후 1차 캐시에 저장한 데이터를 ThreadB 에서도 1차 캐시를 통해 데이터를 가져오고 값을 바꿀수 있게 되었다.
따라서, EntityManager 를 쓰레드간 공유하게 되면 심각한 데이터 오류, 정합성 문제가 발생할 것이다.
728x90
'JPA' 카테고리의 다른 글
다양한 연관관계 매핑과 설정에 따른 트레이드 오프 (0) | 2021.12.31 |
---|---|
테이블과 컬럼에 대한 명세를 엔티티에 자세하게 적는것이 좋은지? (0) | 2021.12.29 |
AllocationSize 를 통한 성능 최적화 (0) | 2021.12.28 |
기본키 매핑 전략에 따른 INSERT QUERY 실행 시점 (0) | 2021.12.28 |
JPA 는 과연 1차 캐시를 통해서 Repeatable Read 를 지원할까? (0) | 2021.12.27 |