SQL 중심적인 개발의 문제점
만약 다음과 같은 class가 있고, 이와 같은 모양에 테이블이 있다고 가정해보자.
그렇다면 해당 테이블에 대한 CRUD문은 다음과 유형을 가질 것이다.
그런데 만약 여기서 tel이라는 이름으로 연락처를 추가해야 한다면 어떻게 될까?
class에 tel을 추가하는 건 기본이며, 해당 테이블과 관련된 CRUD 쿼리를 사용하는 모든 곳들을 수정해줘야 한다.
현실적인 대안은 관계형 데이터베이스
NoSQL이 분산 환경에서 단순 검색 및 추가 작업을 위한 키 값을 최적화할 수 있고, 지연과 처리율이 우수하다는 등 NoSQL 분명히 많은 장점이 있지만
현실에 있는 데이터들은 각각의 연관 관계로 이루어져있기 때문에 결국 현실적인 대안은 관계형 데이터베이스를 써야 한다.
객체와 관계형 데이터베이스의 차이
- 상속
- 객체 : 부모가 가지고 있는 속성 및 기능들을 물려받는다.
- 데이터베이스 : 실질적인 상속은 없지만 각 테이블의 공통되는 속성을 별개의 테이블로 만들고,
해당 테이블의 키 값을 외래 키로 갖는다. (슈퍼 타입 ←→ 서브 타입)
- 연관 관계
- 객체 : 참조를 사용한다. (예시 : member.getTeam())
- 테이블 : 외래키를 사용한다. (예시 : JOIN ON M.TEAM_ID = T.TEAM_ID)
- 데이터 타입
- 데이터 식별 방법
JPA
- JPA : Java Persistence API
- Java 진영의 ORM 기술 표준
ORM
- ORM : Object Relational Mapping (객체 관계 매핑)
- 객체는 객체대로 설계
- 관계형 데이터베이스는 관계형 데이터베이스대로 설계
- ORM 프레임워크가 중간에서 매핑
- 대중적인 언어에는 대부분 ORM 기술이 존재
JPA의 특징
- JPA는 애플리케이션과 JDBC 사이에서 동작한다.
- JPA는 인터페이스의 모음이다. (Hibernate, EclipseLink, DataNucleus)
JPA를 왜 사용해야 하는가?
- SQL 중심적인 개발에서 객체 중심으로 개발
- SQL 작성시 코드 반복의 감소
- 모델링 문제 해결
- 생산성
- 저장 : jpa.persist(member)
- 조회 : Member member = jpa.find(memberId)
- 수정 : member.setName(“변경할 이름”)
- 삭제 : jpa.remove(member)
- 유지보수
- 필요한 항목이 있을 때 필드 하나만 추가해주면 SQL은 JPA가 해결해 준다.
- 패러다임의 불일치 해결
- JPA와 상속
- JPA와 연관관계
- JPA와 객체 그래프 탐색
- JPA와 비교하기 (동일한 트랜잭션 안에서 조회한 엔티티는 서로 같음을 JPA가 보장한다.)
- 성능 최적화
- 캐싱 기능 : 1차 캐시와 동일성 보장
- 버퍼링 기능 : 트랜잭션을 지원하는 쓰기 지연
- 지연 로딩 : 객체가 실제로 사용될 때 로딩하는 전략
- 즉시 로딩 : Join SQL로 한 번에 연관된 객체까지 미리 조회하는 전략
- 데이터 접근 추상화와 벤더 독립성
- 표준
JPA 동작 과정
- 기본 구조
- 애플리케이션과 JDBC 사이에서 동작
- 개발자가 JPA 사용시 JPA 내부에서 JDBC API를 통해서 SQL을 호출하여 DataBase와 통신
- 저장 과정
- 개발자가 저장을 원하는 객체를 JPA에 전달
- JPA가 Entity를 분석
- JPA가 Insert SQL 생성
- JPA가 JDBC API를 사용하여 SQL을 DB에 전송
- 조회 과정
- 개발자가 조회를 원하는 객체의 PK 값을 JPA에 전달
- JPA가 Entity의 매핑 정보를 바탕으로 적절한 Selete SQL 생성
- JPA가 JDBC API를 사용하여 SQL을 DataBase에 전달
- DataBase가 JPA에게 결과를 전달
- JPA가 DataBase한테 전달받은 결과를 객체에 매핑하여 전달
1차 캐시와 동일성 보장
- 같은 트랜잭션 안에서는 동일한 class를 사용하는 엔티티는 여러 개가 있어도 모두 동일한 것으로 취급한다.
- DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repeatable Read를 보장한다.
쓰기 지연 (INSERT)
- 트랜잭션을 커밋할 때까지 INSERT SQL을 모은다.
- JDBC BATCH SQL 기능을 사용해서 한번에 SQL을 전송한다.
쓰기 지연 (UPDATE/DELETE)
- UPDATE, DELETE로 인한 ROW LOCK 시간 최소화
- 트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고 바로 커밋
지연 로딩과 즉시 로딩
- 지연로딩 : 객체가 실제 사용될 때 로딩
- 즉시 로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회