개요
JPA가 하는 일
반복적이고 단순한 SQL을 자동화하여 처리해준다. 과거에는 SQL을 직접 작성해야 했지만, 이제는 JPA에게 시키면 된다.
JPA를 사용해서 얻는 이점
개발 생산성, 개발 속도가 증가하고 유지 보수에 용이하다.
JPA를 실무에서 사용하기 어려운 이유
객체와 테이블을 올바르게 맵핑하고 설계하기 어렵기 때문이다.
SQL 중심적인 개발의 문제점
SQL에 의존적인 개발
우리가 만드는 객체는 관계형 DB에 보관한다. 이 객체를 관계형 DB에 보관하려면, (저장하고/수정하고/삭제하고/조회하고 하려면) 수많은 쿼리 작성이 필요하다. 이게 바로 SQL 중심적인 개발의 문제점이다. 계속해서 INSERT INTO, UPDATE, SELECT, DELETE 쿼리를 무한 반복해야 하기 때문에 지루하다. 또한, 객체에 필드를 하나 추가하려면 모든 쿼리문을 고쳐야 한다는 단점도 있다. 우리는 관계형 DB를 사용해야 하기 때문에 SQL에 의존적인 개발을 피하긴 어렵다.
패러다임의 불일치 (객체 vs 테이블)
객체지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등의 장치를 제공한다. 객체를 저장하는 장소는 주로 관계형 DB를 선택한다. 그럼 객체를 DB에 저장하려면, 객체를에 대한 데이터를 SQL로 바꿔서 DB에 저장해야 한다.
1. 상속
객체에는 상속 관계가 있지만, DB 테이블에는 상속 관계가 없다. 따라서 DB에서 상속 관계를 흉내내려면 부모, 자식의 테이블을 따로 생성하고 필요할 때 JOIN하여 데이터를 들고 온다. 이를 슈퍼타입, 서브타입 관계라고 하며 데이터베이스 설계 기법 중 하나이다.
2. 연관관계
연관관계에 있어서 객체는 참조로 관계를 맺으나 테이블은 외래키를 사용하여 JOIN을 해야 한다. 하지만, 테이블을 객체답게 모델링하게 되면 DB에 INSERT, SELECT 하기가 어려워 진다.
3. 객체 그래프 탐색
객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다. 하지만 DB에서는 개발자가 처음 어떤 SQL을 실행하여 객체를 만들었냐에 따라서 탐색 범위가 결정이 되어 버린다. 이렇게 되면 엔티티에 대한 신뢰 문제가 생긴다. 계층의 아키텍처는 내가 다음 아키텍처를 믿고 쓸 수 있어야 하는데 내가 직접 다음 계층의 코드를 확인해봐야 한다. 결국 진정한 의미의 계층 분할이 어려워지는 것이다.
4. 비교하기
DB에서 같은 memberId를 가진 member를 2번 조회하면 새로운 객체를 만들어 반환하는 것이기 때문에 이 두 인스턴스는 데이터는 같지만 실제로는 다른 인스턴스 2개가 생성되는 것이다. 하지만 자바 컬렉션에서 똑같은 memberId로 인스턴스를 조회하여 비교하게 된다면, 같은 참조 결과가 나온다. 즉 인스턴스 자체가 같은 것이다. 따라서 이때에도 객체와 테이블 사이에 패러다임의 불일치가 생긴다.
결과적으로 객체답게 모델링을 할수록 매핑 작업만 늘어나게 된다.
객체를 Java Collection에 저장하듯이 DB에 저장할 수 없을까? 라는 문제를 해결하는 것이 바로 JPA(Java Persistence API) 기술이다.
JPA 소개
ORM의 개념
Object-relational mapping (객체 관계 매핑), 객체는 객체대로 설계하고, 관계형 DB는 관계형 DB대로 설계한다. 이때 ORM 프레임워크가 중간에서 매핑해준다. 앞서 배운 패러다임의 불일치를 이 ORM이 해결해준다. 대중적인 언어에는 대부분 ORM 기술이 존재한다.
JPA의 개념
Java Persistence API, 자바 진영의 ORM 기술의 표준
JPA는 애플리케이션과 JDBC 사이에서 동작한다. 원래 개발자가 DB에 접근하기 위해 직접 JDBC API를 사용했다면, 이제는 JPA가 대신 사용해준다.
JPA의 구체적인 동작 방식은 아래와 같다.
JPA는 객체를 저장할 때 아래와 같은 4가지 기능을 하는데 이 결과 Java Collection에 저장하듯이 한 줄의 코드만 넣으면 되게끔 해준다.
객체를 조회할 때에도 아래와 같은 4가지 기능을 수행하여 우리에게 Entity 객체만을 반환해준다.
JPA는 발전 과정에서 표준 명세로 발전하였는데 인터페이스의 모음이라는 의미이다. 현재는 JPA 표준 명세를 구현한 대표적인 구현체가 3가지가 있는데 주로 Hibernate를 주로 사용한다.
JPA를 사용해야 하는 이유
JPA가 중간에서 해결을 해주기 때문에 SQL 중심적인 개발에서 객체 중심으로 개발할 수 있다. 이로 인해 생산성과 유지보수가 늘어나게 된다. 또한 위 4가지의 패러다임 불일치를 해결해주고 성능 개선에도 큰 이점을 준다. 이를 통해 엔티티 계층을 신뢰할 수 있게 된다.
JPA의 성능 최적화 기능
1. 1차 캐시와 동일성(identity)을 보장한다.
JPA는 같은 트랜잭션 안에서는 항상 같은 엔티티를 반환한다. 따라서 같은 트랜잭션에서 같은 memberId를 가진 member 객체를 조회하면 1번째 조회에서는 SQL 쿼리를 날려 조회하지만, 2번째 조회에서는 JPA에 들고 있는 메모리 상에서 조회를 해오기 때문에 전체적으로 SQL은 한 번만 실행된다.
2. 트랙잭션을 지원하는 쓰기 지연(transactional write-behind)
이는 데이터를 버퍼로 모으는 것인데, 트랜잭션을 커밋할 때까지 INSERT SQL을 모은다. 이후 JDBC의 BATCH SQL이라는 기능을 사용하여 한 번에 SQL을 전송할 수 있다. 트랜잭션을 커밋하기 전까지만 데이터를 보내면 되기 때문이다. 이게 바로 버퍼 라이팅이 가능하다는 것이다.
3. 지연 로딩(Lazy Loading), 즉시 로딩(Eager Loading)
JPA는 지연로딩과 즉시로딩을 지원한다. 지연로딩은 객체가 실제 사용될 때 로딩하는 것이고, 즉시로딩은 JOIN SQL로 한 번에 연관된 객체까지 미리 조회하는 것이다. 주로 JPA 개발 시에는 지연로딩으로 세팅을 한 후, 즉시로딩을 끼워 넣는다.
'Spring > SpringBoot&JPA' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 섹션3. 영속성 관리 - 내부 동작 방식 (0) | 2024.03.18 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] 섹션2. JPA 시작하기 (0) | 2024.03.15 |
[스프링부트와 JPA 활용 2] Section2. API 개발 고급 - 준비 (0) | 2023.11.27 |
[스프링부트와 JPA 활용 2] Section1 중 "회원 삭제 API" (0) | 2023.11.22 |
[스프링부트와 JPA 활용 2] Section1. API 개발 기본 (1) | 2023.11.22 |