※ 일본의 한 포스트 글을 번역한 포스트입니다. 오역 및 의역, 직역이 있을 수 있으며 틀린 내용은 지적해주시면 감사하겠습니다.
JPA(Java Persistence API)와 ORM(Object-Relational Mapping)
Java 표준의 ORM(Object-Relational Mapping)이다. ORM은 Java로 말하자면 오브젝트와 데이터 베이스의 맵핑을 하는 역할을 한다.
ORM에 대해서 구체적으로 살펴보자면, 앞서말했듯 어플리케이션의 오브젝트와 데이터 베이스(이하, DB)의 레코드 및 오브젝트 간의 관계와 테이블 간의 관계를 상호 맵핑하는 기법으로, ORM를 실현하기 위한 기능이나 소트프웨어를 OR 맵퍼라고 말한다.
오브젝트 지향, 데이터 저장소에서 릴레이션 데이터 베이스를 사용했을 때, 지금까지는 프로그래밍 방법으로 SQL 쿼리 결과를 1행씩 엮었던 개발자의 부담을 경감시켜주는 기술이다.
JPA가 어떻게 데이터 베이스에 액세스를 할 수 있을까에 대해 말하자면, Entity와 EntityManager를 사용하여 액세스한다.
Entity
데이터베이스 상의 데이터를 맵핑하는 Java의 오브젝트를 Entity라고 부른다. Entity는 메모리상의 Java 오브젝트로, EntityManager를 통해 데이터 베이스와 동기화된다.
JPA에서는 Entity 클래스인지 아닌지(@Entity)나 맵핑에 필요한 정보(@id나 @Column등)을 부가하기 위한 다양한 어노테이션을 제공하고 있다.
EntityManager
Entity와 데이터베이스의 동기화를 위한 역할을 하는 것이 EntityManager이다. EntityManager에는 Persistence Context라고 불리는 Entity를 관리하기 위한 영역이 있다.
데이터 베이스에 액세스하는 경우는 Persistence Context내의 Entity를 획득하거나 새롭게 Entity를 등록할 필요가 있다. 이로 인해 EntityManager가 Entity의 상태를 추적하는 것이 가능해 적당한 타이밍에 데에터 베이스와 동기화한다.
EntityManager에는 Entity 상태를 변경하거나 데이터 베이스와 동기화하기 위한 API가 준비되어 있다.
- Entity Manager에 대한 조작한 타이밍에 데이터 베이스에는 반영되지 않으며 트랜잭션이 커밋 혹은 강제로 동기화(flush)된 타이밍에 Personal Context에 축적한 Entity의 변경사항이 데이터 베이스에 반영된다.
- Personal Context는 트랜잭션 단위이다.
JPA로 할 수 있는 것과 장점
JPA로 할 수 있는 것과 장점은 다음과 같다.
- Entity에는 4개의 상태가 존재한다.
- 테이블간의 관계를 Entity간의 참조관계로 맵핑할 수 있다.
- JPA에 의해 JPQL를 이용한 데이터 액세스를 통해 성능을 향상시킬 수 있다.
- 당연하지만 배타제어를 하는 기능도 존재한다.
이 순서대로 장점을 설명하도록 하겠다.
Entity에는 4개의 상태가 존재한다.
- new 상태 : 새롭게 생성한 인스턴스가 Persistence Context에 미동록된 상태
- 관리 상태 : Persistence Context에 등록된 상태, 동기화 유효
- 분리 상태 : Persistence Context에서 제외된 상태, 원래대로 복귀하는 것도 가능
- 삭제된 상태 : 데이터 베이스에서 삭제될 예정인 상태, 데이터 베이스가 삭제될 때까지 계속된다.
구체적인 설명에 대해서는 쓰지 않겠지만, EntityManager의 API를 사용하는 것으로 위 상태 어떤 것으로든 변경이 가능하다.
테이블간의 관계를 Entity간의 참조관계로 맵핑할 수 있다.
데이터 베이스에서는 테이븐 간의 관계를 나타내기 위해 외부 키를 사용한다. 그러므로 데이터 베이스와 동일하게 JPA에서는 Entity단의 관계를 어노케이션을 사용하여 맵핑할 수 있다(@OneToOne, @OneToMany, @ManyToOne 등).
관계원의 속성에 액세스할 수 있는 것만으로도 관계되어 있는 Entity의 데이터를 획득할 수 있는 것이 JPA의 제일 큰 메리트이다.
여담이지만 관계 Entity 데이터를 획득하기 위한 SQL가 발행되는 타이밍으로 두 가지가 있으며 지정가능하다.
- Lazy 패치 : 관계 Entity의 속성에 액세스되는 테이밍
- Eager패치 : 본체 Entity에 대해서 EntityManager의 API가 실행되는 타이밍
JPA에 의해 JPQL를 이용한 데이터 액세스를 통해 성능을 향상시킬 수 있다.
상세 내용은 다음에 기회가 되면 다루도록 하겠다.
당연하지만 배타제어를 하는 기능도 존재한다.
Web 어플리케이션에서는 여러 개의 트랜잭션이 동시에 실행되는 것이 대부분이라고 생각된다.
참고로 트랜잭션이란 여러 개의 갱신(INSERT, UPDATE, DELETE등) 덩어리이다. 트랜잭션을 종료하려면 COMMIT(확정) 혹은 ROLLBACK(삭제)의 실행이 필요하다.
여러 개의 트랙잭션이 존재하는 경우 베타 제어를 고려해야한다. JPA에서는 낙관적 락과 비관적 락 두 가지 모두 서포트하고 있다.
- 낙관적 락은 갱신 대상의 데이터가 획득될 때와 갱신될 대동일한지 아닌지 확인하고, 동일하면 갱신, 다르면 에러를 발생시킨다.
- 비관적 락은 트랜잭션 시작 직후에 갱신 대상이 되는 레코드의 락을 획득하여, 록된 레코드는 트랙잭션 끝날 때 까지 갱신되지 않는다.
참고자료
'IT > 기초 지식' 카테고리의 다른 글
[DDD] DDD를 실천하기 위한 안내서 (개념/도입편) (1) | 2023.03.18 |
---|---|
[DDD] DDD를 실천하기 위한 안내서 (리포지터리편) (0) | 2023.03.15 |
[Enzyme] shallow와 instance의 차이점 (0) | 2023.03.13 |
[Jest] test.each로 Parameterized test하기 (0) | 2023.03.03 |
[Jest] mock과 jest.fn(), jest.spyOn(), jest.mock()의 간단 사용법 (0) | 2023.03.01 |