Backend/JPA 10

JPA의 낙관적 락과 비관적 락

JPA의 낙관적 락과 비관적 락 JPA에서 @Transactional(isolation = Isolation.DEFAULT) 로 설정하면 DBMS에 설정한 격리 수준을 따른다. MySQL은 REPEATABLE READ가 기본 설정이다. 그리고 JPA는 영속성 컨텍스트와 1차 캐시를 통해 REPEATABLE READ 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공한다. 그런데 일부 로직에서 더 높은 격리 수준이 필요할 때가 있다. 따라서 이때 JPA가 제공하는 낙관적 락과 비관적 락 옵션을 사용하면 된다. 낙관적 락: 대부분의 트랜잭션이 충돌이 발생하지 않을 것이라고 낙관적으로 가정하는 방법이다. 따라서 데이터베이스가 제공하는 락 기능을 사용하지 않고, JPA가 제공하는 버전 관리 기능을 사용한..

Backend/JPA 2024.02.07

준영속 상태에서의 지연 로딩 문제와 그 해결법인 OSIV

트랜잭션 범위의 영속성 컨텍스트 전략 스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용한다. 이름 그대로 트랜잭션의 범위와 영속성 컨텍스트의 생존 범위가 같다는 뜻이다. 즉, 트랜잭션을 시작할 때 영속성 컨텍스트를 생성하고 트랜잭션이 끝날 때 영속성 컨텍스트를 종료한다. 그리고 같은 트랜잭션 안에서는 항상 같은 영속성 컨텍스트에 접근한다. 스프링 프레임워크를 사용하면 보통 비즈니스 로직을 시작하는 서비스 계층에서 @Transactional 어노테이션을 선언해서 트랜잭션을 시작한다. @Transactional 어노테이션이 있으면 해당 클래스의 메소드 호출시 메소드 실행 직전에 스프링의 트랜잭션 AOP가 먼저 동작한다. 트랜잭션 AOP는 대상 메소드를 호출하기 직전에 트랜잭션을 시작한다..

Backend/JPA 2024.02.04

엔티티 조회 성능 최적화

xToOne 관계의 엔티티 조회 성능 최적화 Order를 조회할 때 연관된 Member와 Delivery를 함께 조회한다고 가정하자. 이때 Order와 Member는 다대일 관계이고, Order와 Delivery는 일대일 관계이다. 지연 로딩 사용으로 인한 N+1 문제 지연 로딩으로 설정해두면, Order를 조회할 때 Member와 Delivery 테이블에는 조회 쿼리가 나가지 않고, 연관된 엔티티인 Member와 Delivery는 프록시 객체가 된다. 그리고 member.getUsername()과 같이 엔티티에 접근할 때, Member 테이블에 조회 쿼리가 나가게 되고, 해당 프록시 객체가 초기화된다. 따라서 만약 주문 정보(Order)를 조회하면서 회원 정보(Member)와 배송 정보(Delivery..

Backend/JPA 2024.02.02

값 타입 컬렉션

JPA의 데이터 타입 JPA의 데이터 타입을 크게 분류하면 엔티티 타입과 값 타입으로 나눌 수 있다. 엔티티 타입 @Entity로 정의하는 객체 데이터가 변해도 식별자를 통해 지속적으로 추적이 가능하다. 값 타입 종류 기본 값 타입: 기본 타입, 래퍼 클래스 , String처럼 자바가 제공하는 기본 데이터 타입 임베디드 타입: JPA에서 사용자가 정의한 값 타입 컬렉션 값 타입: 두개 이상의 값 타입을 저장할 때 사용 식별자가 없으므로 변경시 추적이 불가능하며 생명주기를 엔티티에 의존한다. 값 타입 컬렉션(컬렉션 값 타입) 값 타입을 두개 이상 저장하려면 컬렉션에 보관하고, @ElementCollection과 @CollectionTable을 사용하면 된다. @Entity public class Membe..

Backend/JPA 2024.01.13

JPQL의 소개와 기본 문법

JPQL JPQL은 Java Persistence Query Language의 약자로, JPA가 지원하는 객체지향 쿼리 언어이다. ORM을 사용하면 데이터베이스 테이블이 아닌 엔티티 객체를 대상으로 개발하므로 검색도 테이블이 아닌 엔티티 객체를 대상으로 하는 방법이 필요하다. JPQL은 이런 문제를 해결하기 위해 만들어졌다. JPQL의 특징은 다음과 같다. SQL이 데이터베이스 테이블을 대상으로 하는 데이터 중심의 쿼리라면, JPQL은 객체를 대상으로 하는 객체지향 쿼리이다. SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다. JPQL은 결국 SQL로 변환된다. JPQL을 사용하면 JPA는 이 JPQL을 분석한 다음 적절한 SQL을 만들어 데이터베이스를 조회한다. 그리고 조회한 결과로 엔티티..

Backend/JPA 2024.01.10

영속성 전이(cascade)와 고아 객체

영속성 전이(cascade) 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶으면 영속성 전이 기능을 사용하면 된다. 예를 들어 엔티티를 저장하거나 삭제할 때 연관된 엔티티도 함께 저장하거나 삭제하는 경우이다. JPA는 cascade 옵션으로 영속성 전이를 제공한다. public enum CascadeType { ALL, // 모두 적용 PERSIST, // 양속 MERGE, // 병힙 REMOVE, // 삭제 REFRESH, // REFRESF DETACH // DETACH } cascade 옵션 적용 전 예를 들어 다음과 같이 부모와 자식이 일대다 관계로 정의되어 있다고 하자. @Entity public class Parent { @Id @GeneratedValue pr..

Backend/JPA 2024.01.09

프록시와 지연 로딩

프록시가 필요한 이유 다음 예제는 회원 엔티티를 찾아서 회원과 팀의 이름을 출력한다. Member member = em.find(Member.class, memberId); Team team = member.getTeam(); System.out.println("회원 이름: " + member.getName()); System.out.println("팀 이름: " + team.getName()); 반면 다음 예제는 회원 엔티티를 찾아서 회원의 이름만 출력하고, 회원과 관련된 팀 엔티티는 전혀 사용하지 않는다. Member member = em.find(Member.class, memberId); Team team = member.getTeam(); System.out.println("회원 이름: " + ..

Backend/JPA 2024.01.09

양방향 연관관계 매핑

객체와 테이블의 차이 객체의 양방향 연관관계: 정확히 말하자면 객체에는 양방향 연관관계가 없다. 서로 다른 단방향 연관관계 2개가 양방향처럼 보일 뿐이다. 회원 -> 팀 팀 -> 회원 테이블의 양방향 연관관계: 반면 데이터베이스 테이블은 외래 키 하나로 양쪽에서 서로 조인할 수 있다. 즉 외래 키 하나로 두 테이블은 양방향 연관관계를 맺는다. 회원 팀 테이블은 외래 키 하나로 두 테이블의 연관관계를 관리한다. 따라서 엔티티를 단방향으로 매핑하면(단방향 연관관계), 참조를 하나만 사용하므로 이 참조로 외래 키를 관리하면 된다. 그런데 엔티티를 양방향으로 매핑하면(양방향 연관관계), '회원 -> 팀', '팀 -> 회원' 두 곳에서 서로를 참조한다. 즉 테이블의 외래 키는 하나인데, 객체에서 연관관계를 관리하..

Backend/JPA 2024.01.09

기본 키 매핑

JPA의 기본 키 매핑 JPA는 엔티티들을 영속성 컨텍스트에서 관리하는데, 영속성 컨텍스트에서 관리되려면 엔티티를 구분할 수 있는 식별자가 반드시 필요하다. 식별자가 되는 필드는 엔티티 클래스에서 @Id 어노테이션을 통해 지정할 수 있다. JPA가 제공하는 기본 키 생성 전략은 다음과 같다. 직접 할당: 기본 키를 애플리케이션에서 직접 할당한다. 자동 생성 IDENTITY: 기본 키 생성을 데이터베이스에 위임한다. SEQUENCE: 데이터베이스 시퀀스를 사용해서 기본 키를 할당한다. TABLE: 키 생성 테이블을 사용한다. 자동 생성 전략이 이렇게 다양한 이유는 데이터베이스 벤더마다 지원하는 방식이 다르기 때문이다. 예를 들어 오라클은 시퀀스를 제공하지만 MySQL은 시퀀스를 제공하지 않고 그 대신에 기..

Backend/JPA 2024.01.09

엔티티 매니저와 영속성 컨텍스트

엔티티 매니저 팩토리(entity manager factory), 엔티티 매니저(entity manager) 엔티티 매니저는 엔티티를 저장, 수정, 삭제, 조회하는 등 엔티티와 관련된 모든 일을 처리한다. 이름 그대로 엔티티를 관리하는 관리자이다. 엔티티 매니저 팩토리는 이름 그대로 엔티티 매니저를 만드는 공장인데, 엔티티 매니저 팩토리를 생성하는 비용은 매우 크다. 따라서 한 개만 생성해서 애플리케이션 전체에서 공유하도록 설계되어 있다. 반면, 공장에서 엔티티 매니저를 생성하는 비용은 거의 들지 않는다. 그리고 엔티티 매니저 팩토리는 여러 스레드가 동시에 접근해도 안전하므로 서로 다른 스레드 간에 공유해도 되지만, 엔티티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 스레드 간에 절대..

Backend/JPA 2024.01.05