Application/JPA

    [JPA] 1차 캐시 vs 2차 캐시

    JPA에 대해서 헷갈렸던 개념들을 위주로 정리하는 글입니다. 1차 캐시와 2차 캐시 네트워크를 통해 데이터베이스에 접근하는 시간 비용은 애플리케이션 서버 내부 메모리에 접근하는 시간보다 훨씬 비싸다. 따라서 조회한 데이터를 메모리에 캐싱해 두면 데이터베이스 접근 횟수를 줄여 성능을 개선할 수 있다. 1차 캐시 영속성 컨텍스트 내부에는 엔티티를 보관하는 저장소가 있는데 이를 1차 캐시라고 한다. 일반적으로 트랜잭션을 시작하고 종료할 때까지만 1차 캐시가 유효하다. OSIV를 사용하더라도 사용자의 요청이 들어올 때부터 끝날 때까지만 1차 캐시가 유효하다. 특징 같은 엔티티가 있으면 객체 동일성을 보장한다. (==) 2차 캐시 애플리케이션 범위의 캐시로, 공유 캐시라고도 한다. 따라서 애플리케이션을 종료할 때..

    [JPA] @Transaction(readOnly=true) 성능 향상 이유?

    개요 스프링 프레임워크에서 어노테이션으로 트랜잭션을 읽기 전용 모드로 설정할 수 있다. @Transactional(readOnly = true) 예상치 못한 엔티티의 등록, 변경, 삭제를 예방할 수 있고, 또한 성능을 최적화할 수 있습니다. 하지만 왜?? 성능을 최적화 할 수 있는지는 알지 못했습니다. 그래서 정리해본 글입니다. 읽기 전용 쿼리의 성능 최적화 엔티티가 영속성 컨텍스트에 관리되면 1차 캐시부터 변경 감지까지 얻을 수 있는 혜택이 많다. 하지만 영속성 컨텍스트는 변경 감지를 위해서 스냅샷 인스턴스를 보관하므로 더 많은 메모리를 사용하는 단점이 존재한다. 혹시 영속성 컨텍스트와 변경 감지가 동작하는 원리에 대한 정보는 아래 글을 참고해주세요. [JPA] 영속성 컨텍스트란? JPA에 대해서 헷갈..

    [JPA] 영속성 컨텍스트와 트랜잭션, OSIV

    JPA에 대해서 헷갈렸던 개념들을 위주로 정리하는 글입니다. OSIV 위의 모든 문제는 엔티티가 프레젠테이션 계층에서 준영속 상태이기 때문에 발생한다. 영속성 컨텍스트를 뷰까지 살아있게 열어두는 것을 OSIV라고 한다. 즉, OSIV란 영속성 컨텍스트를 뷰까지 열어둔다는 뜻이다. 과거의 OSIV: 요청 당 트랜잭션 요청이 들어오자마자 서블릿 필터나 스프링 인터셉터에서 영속성 컨텍스트를 만들면서 트랜잭션을 시작하고 요청이 끝날 때 트랜잭션과 영속성 컨텍스트를 함께 종료한다. 문제점 컨트롤러나 뷰 같은 프레젠테이션 계층이 엔티티를 변경할 수 있다는 점. 해결 방법 - 엔티티를 읽기 전용 인터페이스로 제공 - 엔티티 래핑 - DTO만 반환 스프링 OSIV: 비즈니스 계층 트랜잭션 과거의 OSIV는 요청 당 트..

    [JPA] 트랜잭션 범위와 영속성 컨텍스트, Fascade 계층

    JPA에 대해서 헷갈렸던 개념들을 위주로 정리하는 글입니다. 스프링 IoC 컨테이너 환경에서 JPA가 동작하는 내부 동작 방식을 이해하고, 컨테이너 환경에서 웹 애플리케이션을 개발할 때 발생할 수 있는 다양한 문제점과 해결 방안을 알아보자. 트랜잭션 범위의 영속성 컨텍스트 1. 스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용한다. 즉, 트랜잭션 범위와 영속성 컨텍스트의 생존 범위가 같다는 뜻으로 트랜잭션을 시작할 때 영속성 컨텍스트를 생성하고 트랜잭션이 끝날 때 영속성 컨텍스트틀 종료한다. 트랜잭션을 커밋하면 JPA는 먼저 영속성 컨텍스트를 플러시해서 변경 내용을 데이터베이스에 반영한 후에 데이터베이스 트랜잭션을 커밋한다. (만약 예외가 발생해서 트랜잭션을 롤백하고 종료하면 플러시..

    [JPA] JPQL 객체지향 쿼리 심화

    JPA에 대해서 헷갈렸던 개념들을 위주로 정리하는 글입니다. 벌크 연산 엔티티를 수정하려면 영속성 컨텍스트의 변경 감지 기능이나 병합을 사용하고, 삭제하려면 EntityManager.remove() 메소드를 사용한다. 하지만 수백 개 이상의 엔티티를 하나씩 처리하기에는 시간이 너무 오래 걸린다. 이럴 때 여러 건을 한 번에 수정하거나 삭제하는 벌크 연산을 사용하면 된다. (executeUpdate() 사용) // 벌크 연산: 수정 String qlString = "update Product p" + "set p.price = p.price * 1.1" + "where p.stockAmount < :stockAmount"; int resultCount = em.createQuery(qlString) .se..