개요실무 중 Querydsl을 사용할 때 조금 더 편하게 사용할 방법이 없을까 생각하다가 모듈화(?)라고 하긴 그렇지만 사용하기 쉽고 가독성이 좋도록 구현해 보았습니다. 파일 구조구현한 파일은 4가지입니다. QuerydslConfig.java@Configurationpublic class QuerydslConfig { @PersistenceContext private EntityManager entityManager; @Bean public JPAQueryFactory jpaQueryFactory() { return new JPAQueryFactory(JPQLTemplates.DEFAULT, entityManager); }}해당 클래스는 아시다시피 JPAQueryF..
JPA
반응형
하이버네이트와 EHCACHE 적용 하이버네이트와 EHCACHE(ehcache.org)를 사용해서 2차 캐시를 적용해보자. 하이버네이트가 지원하는 캐시는 크게 3가지가 있다. 엔티티 캐시 엔티티 단위로 캐시한다. 식별자로 엔티티를 조회하거나 컬렉션이 아닌 연관된 엔티티를 로딩할 때 사용한다. 컬렉션 캐시 엔티티와 연관된 컬렉션을 캐시한다. 컬렉션이 엔티티를 담고 있으면 식별자 값만 캐시한다.(하이버네이트 기능) 쿼리 캐시 쿼리와 파라미터 정보를 키로 사용해서 캐시한다. 결과가 엔티티면 식별자 값만 캐시한다.(하이버네이트 기능) 참고로 JPA 표준에는 엔티티 캐시만 정의되어 있다. 환경설정 build.gradle에 cache 라이브러리를 추가한다. dependencies { // https://mvnrepo..
JPA 구현체 대부분은 2차 캐시 기능을 각자 지원했는데 JPA는 2.0에 와서야 2차 캐시 표준을 정의했다. JPA 2차 캐시 표준은 여러 구현체가 공통으로 사용하는 부분만 표준화해서 세밀한 설정을 하려면 구현체에 의존적인 기능을 사용해야 한다. 캐시 모드 설정 2차 캐시를 사용하려면 엔티티에 javax.persistence.Cacheable 어노테이션을 사용하면 된다. @Cacheable은 @Cacheable(true), @Cacheable(false)로 설정할 수 있는데 기본값은 true다. @Cacheable // true @Entity public class Member { ... } 다음과 같이 설정해서 원하는 패키지에만 캐시를 적용할 수 도 있다. @Primary @Bean(name = "e..
네트워크를 통해 데이터베이스에 접근하는 시간 비용은 애플리케이션 서버에서 내부 메모리에 접근하는 시간 비용보다 수만에서 수십만 배 이상 비싸다. 따라서 조회한 데이터를 메모리에 캐시 해서 데이터베이스 접근 횟수를 줄이면 애플리케이션 성능을 획기적으로 개선할 수 있다. 그래서 1차, 2차 캐시가 뭔데? 영속성 컨텍스트 내부에는 엔티티를 보관하는 저장소가 있는데 이것을 1차 캐시라 한다. 이것으로 얻을 수 있는 이점이 많지만 일반적인 웹 애플리케이션 환경은 트랜잭션을 시작하고 종료할 때까지만 1차 캐시가 유효하다. 따라서 애플리케이션 전체로 보면 데이터베이스 접근 횟수를 획기적으로 줄이지는 못한다. 하이버네이트를 포함한 대부분의 JPA 구현체들은 애플리케이션 범위의 캐시를 지원하는데 이것을 공유 캐시 또는 ..
이 전 블로그 글에는 낙관적 락(Optimistic Lock)과 비관적 락(Pessimistic Lock)이 무엇인지 알아보았다. 이제 JPA에서 낙관적 락과 비관적 락을 어떻게 사용하는지 알아보자. JPA 락 사용(Lock) 락은 다음 위치에 적용할 수 있다. EntityManager.lock(), EntityManager.find(), EntityManager.refresh() Query.setLockMode() (TypeQuery 포함) @NamedQuery // 조회 시 Locking Board board = em.find(Board.class, id, LockModeType.OPTIMISTIC); // 조회 후 필요할 때 Locking Board board = em.find(Board.class..
JPA는 데이터베이스 트랜잭션 격리 수준을 READ COMMITTED 정도로 가정한다. 만약 일부 로직에 더 높은 격리 수준이 필요하면 낙관적 락과 비관적 락 중 하나를 사용하면 된다. 낙관적 락 트랜잭션 대부분은 충돌이 발생하지 않는다고 낙관적으로 가정하는 방법이다. 이것은 데이터베이스가 제공하는 락 기능을 사용한 것이 아니라 JPA가 제공하는 버전 관리 기능을 사용한다. 쉽게 이야기해서 애플리케이션이 제공하는 락이다. 낙관적 락은 트랜잭션을 커밋하기 전까지는 트랜잭션의 충돌을 알 수 없다는 특징이 있다. 비관적 락 트랜잭션의 충돌이 발생한다고 가정하고 우선 락을 걸고 보는 방법이다. 이것은 데이터베이스가 제공하는 락 기능을 사용한다. 대표적으로 select for update 구문이 있다. 두 번의 ..
트랜잭션은 ACID라 하는 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability)을 보장해야 한다. 원자성 트랜잭션 내에서 실행한 적업들은 마치 하나의 작업인 것처럼 모두 성공 또는 모두 실패해야 한다. 일관성 모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 한다. 예를 들어 데이터베이스에서 정한 무결성 제약 조건을 항상 만족해야 한다. 격리성 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 격리한다. 예를 들어 동시에 같은 데이터를 수정하지 못하도록 해야한다. 격리성은 동시성과 관련된 성능 이슈로 인해 격리 수준을 선택할 수 있다. 지속성 트랜잭션을 성공적으로 끝내면 그 결과가 항상 기록되어야 한다. 중간에 시스템에 문제..
트랜잭션을 지원하는 쓰기 지연과 JDBC 배치 insert(member1); // INSERT INTO ... insert(member2); // INSERT INTO ... insert(member3); // INSERT INTO ... insert(member4); // INSERT INTO ... insert(member5); // INSERT INTO ... commit(); 위와 같은 경우는 5번에 INSERT SQL과 1번의 커밋으로 총 6번 데이터베이스와 통신한다. 이것을 최적화 하려면 SQL을 모아 한 번에 데이터베이스로 보내면 된다. JDBC가 제공하는 SQL 배치 기능을 사용하면 SQL을 모아서 데이터베이스에 한 번에 보낼 수 있다. 하지만 이 기능을 사용하려면 코드의 많은 부분을 수정..
수백만 건의 데이터를 배치 처리해야 하는 상황이라 가정해보자. 일반적인 방식으로 엔티티를 계속 조회하면 영속성 컨텍스트에 아주 많은 엔티티가 쌓이면서 메모리 부족 오류가 발생한다. 따라서 이런 배치 처리는 적절한 단위로 영속성 컨텍스트를 초기화 해야한다. 또한, 2차 캐시를 사용하고 있다면 2차 캐시에 엔티티를 보관하지 않도록 주의해야 한다. JPA 등록 배치 많은 엔티티를 한 번에 등록할 때 주의점은 영속성 컨텍스트에 엔티티가 계속 쌓이지 않도록 일정 단위마다 영속성 컨텍스트의 엔티티를 데이터베이스에 플러시하고 영속성 컨텍스트를 초기화해야 한다. EntityManager em = entityManagerFactory.createEntityManager(); EntityTransaction tx = em..
엔티티가 영속성 컨텍스트에 관리되면 1차 캐시부터 변경 감지까지 얻을 수 있는 혜택이 많다. 하지만 영속성 컨텍스트는 변경 감지를 위해 스냅샷 인스턴스를 보관하므로 더 많은 메모리르 사용하는 단점이 있다. 예를 들어 100건의 구매 내용을 출력하는 단순한 조회 화면이 있다고 가정해보자. 그리고 조회한 엔티티를 다시 조회할 일도 없고 수정할 일도 없이 딱 한 번만 읽어서 화면에 출력하면 된다. 이때는 읽기 전용으로 엔티티를 조회하면 메모리 사용량을 최적화할 수 있다. 스칼라 타입으로 조회 가장 확실한 방법은 다음처럼 엠티티가 아닌 스칼라 타입으로 모든 필드를 조회하는 것이다. 스칼라 타입은 영속성 컨텍스트가 결과를 관리하지 않는다. select o.id, o.name, o.price from Order o..