김영한 강사님의 '자바 ORM 표준 JPA 프로그래밍-기본편' 강의 정리
2022.03.17~03.31 진행
강의를 듣고 개인적으로 정리한 글입니다. 코드와 그림 출처는 김영한 강사님께 있습니다. 문제 있을 시 알려주세요.
JPA와 모던 자바 데이터 저장 기술
Java와 같은 객체지향 언어로 실무 개발을 할 때에는 주로 관계형 DB를 사용한다.
문제는 애플리케이션은 객체지향적으로 개발을 해야하는데, SQL을 계속 날려야 하기 때문에 SQL 중심적인 개발이 되는 것이다.
1. SQL 중심적인 개발의 문제점
SQL 중심적인 개발은 다음과 같은 문제가 있다.
- 무한반복, 지루한 코드 → SQL 매핑에 많은 시간소요(노가다)
- 객체 CRUD 코드에 필드가 추가 될 경우 SQL을 일일히 고쳐주어야 한다 → 유지보수성 ↓
객체를 RDB에 저장할 경우 또 다른 문제가 있다.
1.1. 패러다임의 불일치
객체와 RDB는 구조 및 기능의 차이가 있기 때문에 어떻게 변환해서 오고갈지가 문제이다.
다음과 같은 기능들이 불일치하다.
- 상속
- 연관관계
- data 타입
- data 식별방법
상속
우선 상속은 객체에는 있지만 RDB에는 없는 기능이다(Table 슈퍼타입, 서브타입 관계와 유사)
Item을 상속하는 Album, Movie, Book 이 있다고 하자.
- 자바는 컬레션에 객체를 저장한다.
- 테이블의 경우 ITEM을 상속받는 테이블들은 ITEM_ID를 pk,fk로 가진다.
객체를 저장하고 조회하는 방식이 이렇게 다르다.
Album | 객체지향 언어(Java)의 경우 | → RDB의 경우 |
---|---|---|
객체 저장 | 자바 컬렉션에 저장 list.add(album); | 1. 객체 분해 2. insert into item (공통속성 저장) 3. insert into album (나머지 속성 저장) |
객체 조회 | Album album = list.get(albumId); 또는 Item item = list.get(albumId); | 1. Item-Album 조인 쿼리 2. 필요한 것을 album에 3. 필요한 것을 item에 |
연관관계
- 객체는 ‘참조’를 사용하므로 한 방향으로만 이동가능하다.
- 테이블은 외래키(foreign key)를 사용하므로, 조인하여 양방향으로 이동할 수 있다.
객체 모델링 저장
Java : member.getTeam().getId();(TEAM_ID를 얻는다)
→ DB : INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES ...
객체 모델링 조회
DB : JOIN ON M.TEAM_ID = T.TEAM_ID
→ Java : Member, Team 객체 생성해서 정보 모두 셋팅(setter), 회원과 팀 관계 설정(setter)
=> 문제: 번거롭다. 슈퍼 DTO 만들어서 다 때려박는게 차라리 생상성 높음
1.2. 객체 그래프 탐색이 자유롭지 X
객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다.
그런데 처음 실행하는 SQL에 따라 탐색 범위가 결정된다. 필드에 있다고 해서 마음껏 값을 꺼내지 못한다.
SELECT M*, T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
위 SQL을 실행한 후에 member.getOrder();를 한다면? null이 나온다. SQL에서 Order을 조회하지 않았기 때문이다.
따라서 엔티티 신뢰 문제가 발생한다. SQL로 어떤 것을 불러올 수 있는지 확인해야 엔티티를 컨트롤 할 수 있다. 그런데 그렇다고 모든 객체를 미리 로딩할 수는 없는 노릇이다.
⇒ 계층형 아키텍처인데도 불구하고 진정한 의미의 (논리적)계층 분할이 어렵다.
1.3. 비교하기 문제 발생
- 자바 컬렉션에 저장하면 id가 같을 경우 같은 객체이다.
- RDB에서 꺼내서 id가 같더라도, new 하는이상 다른 객체로 인식된다.
⇒ 객체 답게모델링 할 수록 매핑 작업만 늘어나고 더 힘들어진다.
객체를 자바 컬렉션에 저장하듯이 DB에 저장할 수 없을까? 고게 바로 JPA!
2. JPA 소개
JPA란 Java Persistence API의 줄임말로, 자바 진영의 ORM 기술 표준이다.
ORM이란 Object-relational mapping의 줄임말로, 객체 관계 매핑을 뜻한다.
객체와 관계형 데이터베이스를 각각 설계하고 나면, ORM 프레임워크로 중간에서 매핑을 할 수 있다.
대중적인 언어는 대부분 ORM 기술이 존재한다.
JPA는 애플리케이션과 JDBC 사이에서 동작한다.
JPA는 인터페이스의 모음일 뿐이고(표준명세, 껍데기), JPA의 구현체에는 하이버네이트, EclipseLink, DataNucleus 3가지가 있다.
2.1. JPA를 왜 사용해야 하는가?
- 패러다임의 불일치 해결
- JPA가 SQL을 처리한다.
- 생산성 증가
- 유지보수가 쉬워짐 (필드 추가 시 모든 SQL을 수정할 필요가 없다)
- 성능 최적화
- 데이터 접근 추상화와 벤더 독립성
- 표준
따라서 SQL 중심적인 개발에서 객체 중심으로 개발할 수 있게 된다.
2.2. 패러다임 불일치 해결
1. JPA와 상속
상속 관계에서, 자바 컬렉션은 한번에 저장이 되는데 DB는 쿼리를 두 번이나 날려야 했다.
다음과 같이 저장하는 코드만 작성하면 JPA가 쿼리를 알아서 처리해준다.
jpa.persist(album); //Album 저장, JPA : INSERT INTO ITEM, INSERT INTO ALBUM
Album album = jpa.find(Album.calss, albumId); //Album 조회, JPA : SELECT I.*, A.* ..
2. JPA와 연관관계, 객체 그래프 탐색
JPA의 지연로딩을 사용하면 실제로 객체 데이터를 사용하는 시점에 SQL이 나가게 된다.
마치 자바 컬렉션에 넣고 꺼내듯 자바코드를 짜도 자유롭게 객체 그래프 탐색이 가능하다.
따라서 엔티티, 계층을 신뢰할 수 있게 된다.
member.setTeam(team); // 연관관계 설정
jpa.persist(member); // Member 저장
Member member = jpa.find(Member.class, memberId); // Member 조회
Team team = member.getTeam(); //member의 team조회, 객체 그래프 탐색
3. 비교하기 - JPA는 동일한 트랜잭션에서 조회한 엔티티는 같음을 보장한다.
2.3. JPA의 성능 최적화 기능
JPA는 데이터를 저장해두는 중간 계층이 있다. 따라서 SQL을 모아두었다가 버퍼링으로 DB에 한번에 보낼 수도 있고, 반대로 DB에서 읽은 것을 모아서 캐싱해두고, 필요할 때 쓸 수도 있다. 이러한 기능들로 성능을 더 끌어올릴 수 있다.
1. 1차 캐시와 동일성 보장
- 같은 트랜잭션 안에서는 같은 엔티티를 반환한다. → 한 번 SQL로 조회한 엔티티는 1차캐시에 저장되서 여러 번 조회 시 1차캐시에서 꺼내진다. ⇒ SQL이 1번만 실행된다
2. 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)
- JDBC BATCH SQL 기능을 사용해서 commit 할 때 한 방에 SQL을 모아서 보낸다(버퍼링)
transaction.begin();
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
//여기까지 INSERT SQL을 보내지 않는다.
transaction.commit(); // DB에 SQL 전송
- UPDATE, DELETE로 인한 로우(ROW)락 시간을 최소화한다.
- 트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고, 바로 커밋
transaction.begin(); // [트랜잭션] 시작
changeMember(memberA);
deleteMember(memberB);
비즈니스_로직_수행(); //비즈니스 로직 수행 동안 DB 로우 락이 걸리지 않는다.
//커밋하는 순간 데이터베이스에 UPDATE, DELETE SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
3. 지연 로딩(Lazy Loading)
JPA는 지연로딩과 즉시로딩의 기능을 제공하는데, 옵션으로 선택 가능하다.
- 지연 로딩: 객체가 실제 사용될 때 DB에 SQL을 보내서 조회한다.
- 즉시 로딩: JOIN SQL로 한번에 연관된 객체까지 미리 조회
'Web > JPA' 카테고리의 다른 글
[Inflearn] JPA - 값 타입(작성전) (0) | 2022.05.11 |
---|---|
[Inflearn] JPA - 객체지향 쿼리 언어 (0) | 2022.03.31 |
[Inflearn] JPA - 엔티티매핑 (0) | 2022.03.22 |
[Inflearn] JPA - 영속성관리 (0) | 2022.03.22 |
[Inflearn] JPA 시작하기 + JPQL이란? (0) | 2022.03.21 |