728x90
JPA 소개
- 애플리케이션 객체 지향 언어 - Java / Scala, Kotiln, ...
- 데이터베이스 세계의 헤게모니 관계형 DB - Oracle, My SQL
- 지금 시대는 객체를 관계형 DB에 관리
- 관계형 DB는 SQL을 짜야 한다. (계속....ㅎㅎㅎㅎ, 옛날 개발자의 일상...ㅎㅎ)
문제점
1. SQL 중심적인 개발의 문제점
- 무한 반복, 지루한 코드
- CRUD
- 자바 객체로 SQL로
- SQL을 자바 객체로
- 객체 생성 → 쿼리 생성 방식으로 진행
- 객체에 필드를 추가한다고 하면?
- 모든 쿼리를 수정해야 한다.
- 이러다 보면, 쿼리 수정 중 하나를 빼먹을 수도 있다.
- 엔티티 신뢰 문제
- A.getB()를 신뢰할 수 있을까?
- SQL에 의존적인 개발을 피하기 어렵다.
2. 패러다임의 불일치 - 객체 vs 관계형 데이터베이스
- RDB는 데이터를 어떻게 정규화해서 저장할지
- 객체는 어떻게 추상화 해서 객체를 관리할지
- 객체 지향 프로그래밍은 추상화, 캡술화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다.
- 객체를 관계형 데이터베이스에 저장
- 객체 → SQL 변환 → SQL → RDB
- 가장 큰 단점은 개발자가 한땀 한땀 해줘야 한다.(SQL 변환, SQL 작성 객체 변환 등등)
- 개발자 == SQL 매퍼
객체와 관계형 데이터베이스의 차이
상속
이때 앨범을 저장한다고 한다면
- 객체 분해 → INSERT INTO ITEM → INSERT INTO ALBUM
조회한다면?
- 각각의 테이블에 조인 SQL 생성 → 각각의 객체 생성 → 복잡 → 더이상 설명은 불가... → DB에 저장할 객체에는 상속 관계 안쓴다.
- 이때, 영화, 책 조회 쿼리를 만든다면 새로운 조인 쿼리를 하나하나씩 만들어줘야 한다.
자바 컬렉션에 저장하면?
List<Item> list = new ArrayList<>(); list.add(album);
자바 컬렉션에 조회한다면
- list.get(albumId);
- 부모 타입으로 조회 후 다형성 활용도 가능
연관관계
- 객체는 참조를 사용: member.getTeam();
- 테이블은 외래 키를 사용 : JOIN ON M.TEAM_ID = T.TEAM_ID
- 이때 Meber가 Team을 갈 수 있는가?
- 객체, 테이블 둘 다 가능
- 그렇다면 Team이 Meber에게 갈 수 있냐?
- 객체에서는 불가능
- 테이블에서는 가능
데이터 타입
테이블에 맞춘 객체 저장
Class Meber { String id; // MEMBER_ID 컬럼 사용 Long teamId; // TEAM_ID FK 컬럼 사용 String username; // USERNAME 컬럼 사용 } class Team { Long id; // TEAM_ID PK 사용 String name; // NAME 컬럼 사용 }
- 이렇게 되면 INSERT가 편리하긴 한데, 객체지향적이지 않다.
객체다운 모델링
class Member { String id; Team team; String username; } class Team { Long id; String name; }
- 이렇게 한다면 member.getTeam().getId()로 INSERT를 하게 된다.
- 그렇다면 SELECT는?
- JOIN 쿼리로 둘다 불러온다 → member 객체 생성 → team 객체 생성 → member.setTeam(team);
- 이렇게 되면 코드가 길어지게 된다.
객체 모델링, 자바 컬렉션에 관리
list.add(member); Member member = list.get(memberId); Team team = member.getTeam();
객체 그래프 탐색
- 객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다.
그러나 처음 실행하는 SQL에 따라 탐색 범위 결정
- 쿼리에서 데이터에 없다면 필드에 null이 들어갈 수 있기 때문이다.
- 바로 이게, 엔티티 신뢰성 문제이다.
따라서 모든 객체를 미리 로딩할 수는 없다.
- 상황에 따라 동일한 회원 조회 메서드를 여러벌 생성
데이터 식별 방법
- 비교하기
- DAO에서 똑같은 ID로 2개의 객체를 불러왔을 때, == 비교시 다르다. (다른 인스턴스이기 떄문이다.)
- 그렇다면 자바 컬렉션에서는?
- 같다.
결론
- 즉, 객체답게 모델링 할수록 매핑 작업만 늘어난다.
- 객체를 자바 컬렉션에 저장 하듯이 DB에 저장할 수는 없을까?
JPA - Java Persistence API
JPA란?
- 자바 진영의 ORM 기술 표준
ORM
- Object-relational Mapping(객체 관계 매핑)
- 객체는 객체대로 설계
- 관계형 데이터베이스는 관계형 데이터베이스대로 설계
- ORM 프레임워크가 중간에서 매핑
- 대중적인 언어에는 대부분 ORM 기술이 존재
JPA는 애플리케이션과 JDBC 사이에서 동작
저장
JPA 소개
- EJB 엔티티 빈(자바 표준) → 하이버네이트(오픈 소스) → JPA(자바 표준)
JPA를 왜 사용해야 하는가?
- SQL 중심적인 개발에서 객체 중심으로 개발
- 생선성, 유지보수, 성능
- 패러다임의 불일치 해결
- 데이터 접근 추상화와 벤더 독립성
- 벤더 독립성이란 Direct만 생성해주면 자동으로 해당 Direct에 맞는 sql을 생성해서 사용 즉, DB가 바뀌더라도 소스 코드가 바뀌지 않는다.
생산성 - JPA와 CRUD
- 조회 : jpa.persit(member)
- 조회 : Member member = jpa.find(memberId)
- 수정 : member.setName("변경할 이름")
- 삭제 - jpa.remove(member)
유지보수
- 기존에는 필드 변경시 SQL 수정
- 그러나 JPA는 필드만 추가하면 JPA가 알아서 SQL를 처리
패러다임의 불일치
상속
저장
개발자가 할일은 아래의 코드를 작성하는 것이다.
jpa.persist(album);
아래의 쿼리는 JPA가 처리해준다.
INSERT INTO ITEM ... INSERT INTO ALBUM ...
조회
개발자가 할일은 아래의 코드를 작성하는 것이다.
Album album = jpa.find(Album.class, albumId);
아래의 쿼리는 JPA가 처리해준다.
SELECT I.*, A.* FROM ITEM I JOIN ALBUM A ON I.ITEM_ID = A.ITEM_ID;
연관관계 저장
member.setTeam(team); jpa.persist(member);
Member meber = jpa.find(Member.class, memberId); Team team = member.getTeam();
- 이때 Team을 사용할때 Team 관련 쿼리 또는 한방 쿼리로 처리한다.
신뢰할 수 있는 엔티티 계층
- 자유로운 객체 그래프 탐색
비교
- 동일한 트랜잭션에서 조회한 엔티티는 같음을 보장
JPA의 성능 최적화 기능
- 1차 캐시와 동일성 보장
- 트랜잭션을 지원하는 쓰기 지연
- 지연 로딩
1차 캐시와 동일성 보장
- 같은 트랜잭션 안에서 같은 엔티티를 반환 - 약간의 조회 성능 향상
트랜잭션을 지원하는 쓰기 지연 - INSERT
- 트랜잭션을 커밋할 떄까지 INSERT SQL을 모음
- JDBC BATCH SQL 기능을 사용해서 커밋시 한번에 SQL 전송
- UPDATE, DELETE로 인한 ROW 락 시간 최소화
- 트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고, 바로 커밋
- 즉, 비지니스 로직 수행 동안 DB ROW 락이 걸리지 않는다.
지연 로딩과 즉시 로딩
- 지연 로딩 : 객체가 실제 사용될 때 로딩
- 이때 필드에 있는 객체는 가짜(프록시) 객체이다.
- 즉시 로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회
결론
- ORM은 객체와 RDB 두 기둥위에 있는 기술
출처
728x90
728x90
'Lecture > [Tacademy] JPA 프로그래밍 기본기 다지기' 카테고리의 다른 글
6. JPA 내부구조 (0) | 2020.12.16 |
---|---|
5. 양방향 매핑 (0) | 2020.12.15 |
4. 연관관계 매핑 (0) | 2020.12.15 |
3. 필드와 컬럼 매핑 (0) | 2020.12.13 |
2. JPA 기초와 매핑 (0) | 2020.12.13 |