SpringBoot 3.x 버전과 호환되는 SpringBoot starter-data-jpa 패키지에는
jakarta.persistence-api:3.1.0 라이브러리가 포함되어 있다
jakarta.persistence-api 라이브러리는 Java Application 개발자가 관계형 데이터베이스를 관리하기 위해
Java 도메인 모델을 사용하는 객체/관계형 매핑 기능을 제공한다
starter-data-jpa 를 사용하는 개발자에겐 익숙한
@Entity, @Table, @Id, @Enumerated 와 같은 어노테이션은 모두 jakarta.persistence-api 라이브러리에서 제공하고 있다
그렇다면, JPA를 잘 이해하고 싶다면 SpringBoot의 기본 제공 라이브러리인 jakarta.persistence-api 라이브러리를 열심히 공부해야 할까?
필자의 의견은 Yes 이다
이 부분에는 합리적인 궁금증이 생길 수 있다
Jakarta의 Persistence API는 JSR 338 스펙의 구현체인데 JPA를 알고 싶으면 JSR 338 스펙을 보는 게 맞지 않나요?
JSR 338은 Java Community Process (JCP)를 통해 정의된 Java Persistence API (JPA) 의 명세이다.
반면에 Jakarta Persistence는 Eclipse Foundation에서 주도하고 있는 Jakarta EE 프로젝트의 일부로,
기존의 JPA를 기반으로 한 데이터 영속성 스펙이다
Oracle과 Eclipse Foundation 사이의 라이선스 및 상표권 문제로 인해 Java EE가 Eclipse Foundation으로 이전되면서 'Jakarta EE'로 이름이 바뀌게 되었고,
이 과정에서 기존의 Java EE 명세의 내용을 계승하면서 몇몇 부분에서 이름만 변경되어야 했기 때문에
원래의 JPA와 Jakarta Persistence 사이에 큰 차이점이 없다
실제로 JSR 338 스펙과 Jakarta Persistence 스펙을 비교해보면 상당 부분 동일한 것을 확인할 수 있다
이는 Jakarta Persistence가 기존의 JPA 스펙을 계승하고 있고
JPA는 이미 오랜 기간 동안 사용되어 오면서 검증된 기술이기에 큰 변화 없이 안정적인 기술로 유지하려는 의도가 있을 수 있다
위와 같은 이유로 필자는 JSR 338 스펙보단 Jakarta Persistence 스펙을 보는 것을 더 권장한다
본론으로 들어가서 이번 시간에는 Jakarta Persistence 스펙에 명시 된 Entity 클래스와, Entity 클래스에 포함 된 인스턴스 변수, 및 접근 유형(Access Type) 에 대해 검토해보고자 한다
Entity Class
- Entity 클래스는 반드시 @Entity 어노테이션이 붙어 있거나, XML descriptor에 entity로 명시되어 있어야 한다
- Entity 클래스는 public 혹은 protected 로 선언 된 인자 없는 생성자가 반드시 존재해야 한다 (필요에 의해 다른 생성자도 가질 수 있다)
- Entity 클래스는 최상위 클래스(top-level class)여야 한다
- Entity 클래스는 인터페이스 혹은 열거형으로 정의해서는 안된다
- Entity 클래스와 포함하는 메서드, 인스턴스 변수들은 final 로 선언할 수 없다
- Entity 인스턴스를 분리된 객체로 값을 전달하려면, Entity 클래스가 Serializable 인터페이스를 구현해야 한다
- Entity는 상속, 연관관계, 다형성 쿼리를 지원한다
- 추상 클래스와, concrete 클래스는 모두 Entity가 될 수 있다
- Entity 클래스는 Non-Entity 클래스를 확장할 수 있으며, 반대의 경우도 가능하다
- Entity 클래스의 인스턴스 변수들은 외부에서 직접 접근해서는 안된다. (getter/setter 와 같은 메서드로 사용자에게 제공해야 한다)
Entity 클래스의 인스턴스 변수
- Entity 클래스의 인스턴스 변수는 사용 여부와 관계 없이 private, protected 혹은 package visibility 해야 한다
- Entity 클래스의 인스턴스 변수에 접근하는 메서드는 public 혹은 protected 접근 제어자를 가져야 한다
- Entity 클래스의 인스턴스 변수에 접근하는 메서드는 JavaBeans 읽기/쓰기 속성에 대한 메서드 네이밍 규칙을 따라야 한다
- 컬렉션 값을 가지는 영속 필드는 Collection, Set, List, Map 인터페이스 중 하나로 정의해야 한다
- 해당 필드에 대한 접근 또한 인터페이스 유형을 통해 이루어져야 한다
- 컬렉션 값을 가지는 영속 필드의 메서드 시그니처는 T 형태여야 한다. ex) List<Order>
- Entity 클래스의 인스턴스 변수에 접근하는 메서드에는 유효성 검증과 같은 비즈니스 로직이 포함되어도 괜찮다
- 위와 같이 메서드에 비즈니스 로직이 포함되는 경우, 호출 순서에 의존해서는 안된다. (persistence provider는 로드하거나 저장할 때, 메서드 호출 순서를 정의하지 않는다)
- Fetch Type이 Lazy로 설정 된 필드에 접근하는 경우, 영속성 컨텍스트에 해당 데이터가 load 되기 전에 직접 접근하지 않아야 한다
- 영속성 컨텍스트가 트랜잭션에 Join 된 경우 접근 메서드에서 발생하는 runtime exception은 transaction rollback 대상으로 표시된다
- Entity 서브 클래스는 속성에 접근하는 메서드를 재정의 할 수 있지만, 속성에 적용되는 객체, 관계형 매핑 메타데이터를 재정의 해서는 안된다
- Entity 클래스에 정의 가능한 필드 속성 유형
- Java primitive types
- String
- 직렬화 가능한 Wrapper Type
- BigInteger
- BigDecimal
- Date
- Calender
- Date
- Time
- Timestamp
- byte[]
- Byte[]
- char[]
- Charater[]
- LocalDateTime
- LocalDate
- LocalTime
- OffsetTime
- OffsetDateTime
- 열거형(Enum) 타입
- Entity 타입
- Entity 컬렉션 타입
- Embeddable 클래스
- Embeddable 클래스 컬랙션 타입
접근 유형 (Access Type)
- field-based 접근, property-based 접근 이 두 가지 유형을 기본적으로 제공한다
- field-based 접근
- 엔티티의 직접적인 필드에 접근하여 데이터를 읽거나 쓰는 방식
- property-based 접근
- getter와 setter 메서드를 통해 데이터에 접근하는 방식
- 두 방식 중 한가지 방식을 채택할 경우, 엔티티 내에서 일관성을 유지해야한다 (혼용해서는 안된다)
- Embeddable 클래스의 Access Type은 매핑 된 상위 클래스(@Embedded 를 명시한 클래스)의 Access Type에 의해 결정 된다
- Access 어노테이션을 통해 다른 Access Type을 지정할 수 있다
Jakarta Spec 문서에서 다루고 있는 정의가 다양하고 깊어, 해당 내용은 게시물 한개로 다루기엔 무리가 있다고 판단하여
시리즈 게시물로 작성하기로 결정했습니다
'개발 > Java' 카테고리의 다른 글
[JPA] Jakarta Spec(JSR 338) - (3)Embeddable Classes (0) | 2023.08.27 |
---|---|
[JPA] Jakarta Spec(JSR 338) - (2)기본 키(PK) 및 Entity ID (0) | 2023.08.23 |
[Java] 상수 값에 행위를 정의하고 싶다면 - Constant Specific Method Implementation (0) | 2023.07.22 |
[Java] 인수값 유효성 검증 - 표현 계층 vs 응용 계층 (0) | 2022.10.23 |
원시 값 포장 [Java] (2) | 2022.04.27 |
댓글