🔅 김영한님의 '자바 ORM 표준 JPA 프로그래밍 - 기본편' 강의를 수강하며 정리한 내용입니다.
1️⃣ SQL 중심적인 개발의 문제점
객체 지향 언어로 개발할 때 아직까지는 관계형 DB가 많이 사용된다.
1. SQL → CRUD 작성의 무한 반복
물론 MyBatis나 spring이 제공하는 JDBC Template의 도움으로 매핑 작업이 줄었어도 개발자가 쿼리문을 모두 작성해야 하는 건 여전히 남아있다.
2. 패러타임의 불일치
객체와 RDB의 차이 → 객체를 DB에 넣을 때의 문제 발생
객체와 관계형 데이터베이스의 차이
1. 상속
DB에 저장할 때는 상속관계를 사용하지 않는다. 따라서 객체를 관계형 DB에 넣고 빼는 과정이 복잡하다.
만약 자바 컬렉션을 활용한다면 add() 나 get()으로 저장, 조회가 단순해진다.
✔ JPA에서는 여러 테이블의 JOIN과 같이 복잡한 쿼리문을 한 번에 실행해서 해결할 수 있다.
2. 연관관계
객체는 참조를 사용해서 연관된 객체를 조회하는 데, 테이블은 외래키를 사용해서 연관관계를 설정하고 조인으로 연관 테이블을 조회한다.
아래 이미지를 보았을 때 객체의 경우 Member 객체에서 Team 객체를 식별할 때 id로 참조할 수 있지만, Team 객체에서는 Member 객체를 식별할 수 없다. (단방향)
이에 반해 테이블은MEMBER와 TEAM 테이블을 TEAM_ID라는 외래키를 사용해서 MEMBER를 통해 TEAM을, TEAM을 통해 MEMBER가 식별 가능하다. (양방향)
3. 객체 그래프 탐색
객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다.
ex) member.getOrder(), member.getTeam() ...
만약 Member와 Team만 데이터를 저장하여 객체를 생성했다고 가정하면 Order에 대한 정보는 존재하지 않기 때문에 member.getOrder()하면 null이 반환될 것이다. → 엔티티의 신뢰 문제 발생!
4. 비교
DB는 PK(기본 키)로 각 로우를 구분하는 반면, 객체는 동일성/동등성 비교를 한다.
식별자가 똑같아도 쿼리문을 통해 결과를 가져오면 객체가 서로 다르다!
String memberId = "100";
Member member1 = memberDAO.getMember(memberId);
Member member2 = memberDAO.getMember(memberId);
member1 == member2; //다르다.
자바컬렉션의 경우 참조 값이 똑같기 때문에 두 객체는 같다!
String memberId = "100";
Member member1 = list.ge(memberId);
Member member2 = list.get(memberId);
member1 == member2; //같다.
2️⃣ JPA 소개
✔ JPA (Java Persistence API) : 자바의 ORM 기술 표준
ORM ❓
- Object-relational mapping(객체 관계 매핑)
- 객체는 객체대로 설계
- 관계형 데이터베이스는 관계형 데이터베이스대로 설계
- ORM 프레임워크가 중간에서 매핑
- 대중적인 언어에는 대부분 ORM 기술이 존재
1. JPA 동작 - 저장
MemberDAO에서 객체를 저장하고 싶다.
- JPA에게 Member 객체 넘기기
- JPA는 Member 객체(Entity)를 분석함
- JPA가 적절한 INSERT 쿼리를 생성함
- JPA가 JDBC API를 사용(통신)해서 INSERT 쿼리를 DB에 보냄
→ 패러다임 불일치 해결
2. JPA 동작 - 조회
DB의 PK 값인 id를 가지고 member를 조회하고 싶다.
- JPA가 매핑 정보를 바탕으로 적절한 SELECT 쿼리를 생성함
- JPA가 JDBC API를 사용해서 INSERT 쿼리를 DB에 보냄
- 반환된 결과 (ResultSet)를 모든 객체에 매핑해줌
생산성 - JPA와 CRUD
- 저장 : jpa.persist(member)
- 조회 : Member member = jpa.find(memberId)
- 수정 : member.setName("변경할 이름")
- 삭제 : jpa.remove(member)
자바의 컬렉션과 같이 함수 호출로 정보 저장, 수정 가능!
유지보수 - 필드만 추가하면 됨, SQL은 JPA가 처리
쿼리문은 손 댈 필요가 없다!
public class Member {
private String memberId;
private String name;
private String tel; // 필드 추가
...
}
JPA의 성능 최적화 기능
1. 1차 캐시와 동일성(Identity) 보장
- 같은 트랜잭션 안에서는 같은 엔티티를 반환, 약간의 조회 성능 향상
- DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repeatable Read 보장
2. 트랜잭션을 지원하는 쓰기 지연 - INSERT
- 트랜잭션을 커밋할 때까지 INSERT SQL을 모음
- JDBC BATCH SQL 기능을 사용해서 한 번에 SQL 전송
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
// 여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
// 커밋하는 순간 데이터베이스에 INSERT SQL을 모아서 보낸다.
transaction.commit(); // [트랜잭션] 커밋
3. 지연 로딩과 즉시 로딩
- 지연 로딩 : 객체가 실제 사용될 때 로딩
ex) Member가 Team 정보를 사용할 때 Member와 Team 객체 모두 조회
- 즉시 로딩 : JOIN SQL로 한 번에 연관된 객체까지 미리 조회
ex) Member를 조회할 때 항상 Team 정보까지 끌어오게끔 설정 가능 → 쿼리문 한 번만 실행 가능
'JPA' 카테고리의 다른 글
[JPA] 연관관계 매핑 - 단방향 연관관계 (0) | 2022.08.07 |
---|---|
[JPA] 엔티티 매핑 (0) | 2022.07.28 |
[JPA] 준영속 상태 (0) | 2022.07.18 |
[JPA] 플러시(Flush) (0) | 2022.07.18 |
[JPA] 영속성 관리 (0) | 2022.07.18 |
댓글