Search
Duplicate
📒

[Spring DB] xx. ORM 개념 ⭐

상태
미진행
수업
Database Study
주제
JPA
연관 노트
3 more properties
참고

객체와 관계형 데이터베이스의 차이

NOTE
1.
상속
객체는 상속 관계가 있지만, 관계형 데이터베이스는 상속 관계가 없다
2.
연관관계
객체는 reference(참조)를 가지고 있다. (ex 연관된 객체를 getter로 가져올 수 있음)
관계형 데이터베이스는 PK나 FK로 join해서 필요한 데이터를 찾을 수 있다
3.
데이터 타입
4.
데이터 식별 방법

JPA

NOTE
Java Persistence API (자바 진영의 ORM 기술 표준)

ORM

Object-relational mapping(객체 관계 매핑)
객체는 객체대로 설계, 관계형 데이터베이스는 관계형 데이터베이스 대로 설계
ORM 프레임워크가 중간에서 매핑해줌
대중적인 언어에서 대부분 ORM기술이 존재한다

JPA 개념

NOTE

JPA는 어플리케이션과 JDBC 사이에서 동작한다

JAVA 어플리케이션에서 JPA에게 명령하면, JPA는 JDBC API를 사용해서 SQL을 만들어서 DB에 보낸다

JPA 사용이유

NOTE
SQL 중식적인 개발 → 객체 중심으로 개발
생산성
유지보수
패러다임 불일치 해결
성능
데이터 접근 추상화와 벤더 독립성
표준

생산성

CRUD가 다 정의되어 편하다
저장 : jpa.persist(member)
조회 : Member member = jpa.find(memberId)
수정 : member.setName(”변경할 이름”)
삭제 : jpa.remove(member)

유지보수

기존에는 필드 변경시 모든 SQL을 수정했어야 했다
ex) 필드 1개가 추가되면, 그것을 사용하는 모든 곳을 수정해야 했음 → 실수 확률 증가
JPA를 사용하면 필드만 추가하면 된다!
ex) db에 column이 추가되었다는 가정하에

JPA 동작

NOTE

저장

JPA에게 Member객체를 넘기면 JPA가 객체를 분석한다
INSERT query생성 (JPA가 query를 생성함!)
JPAJDBC API를 사용해서 INSERT query를 DB에 내보냄
패러다임 불일치 해결!

조회

JPA에게 PK값으로 요청한다
JPA는 SELECT query 생성
JDBC API를 통해 DB에 보내고 결과를 받음
ResultSet 매핑
패러다임 불일치 해결!

JPA와 패러다임 불일치 해결

NOTE
객체와 관계형 데이터베이스는 지향하는 목적이 다르므로 기능과 표현 방법이 다르다

JPA와 상속

NOTE
객체는 상속이 있지만 테이블은 상속이 없다
객체 저장 → 객체를 분해해서 2개의 INSERT 쿼리 사용
객체 조회 → 두 테이블을 join해서 조회한 정보로 객체를 생성
이 과정이 모두 패러다임 불일치를 해결하기 위한 비용이다
JPA를 사용하면 단순히 자바 컬렉션에 저장하듯이 저장하면 된다!
객체 저장
jpa.persist(album);
Java
복사
저장
객체 조회
String albumId = "id100"; Album album = jpa.find(Album.class, albumId);
Java
복사
조회

JPA와 연관관계

NOTE
객체는 참조로 다른 객체와 관계를 맺는다
테이블은 외래 키를 사용해서 다른 테이블과 관계를 맺는다
테이블 중심 모델링 (외래키)
class Member { String id; //MEMBER_ID 컬럼 Long teamId; //TEAM_ID 컬럼 (FK) String username; //USERNAME 컬럼 } class Team { Long id; //TEAM_ID 컬럼 (PK) String name; //NAME 컬럼 }
Java
복사
장점 : 테이블에 저장하거나, 조회할 때 필드를 그대로 사용하기 때문에 편하다
단점 : Member에서 Team으로 객체 참조가 없다
member.getTeam()을 통한 객체 그래프 탐색이 불가능함
객체지향 모델링 (참조)
class Member { String id; //MEMBER_ID 컬럼 Team team; //참조로 연관관계를 맺는다. String username; //USERNAME 컬럼 Team getTeam() {...} } class Team { Long id; //TEAM_ID 컬럼 (PK) String name; //NAME 컬럼 }
Java
복사
장점 :객체 참조가 있어 member.getTeam()을 통한 탐색이 가능함
단점 : 객체를 저장하기 위해 SQL 변환 작업이 늘어난다.
JPA를 통한 연관관계 해결!
JPA는 관계 맺고 있는 객체 참조를 외래 키로 변환해서 INSERT SQL 작성을 해주고, 조회할 때 외래 키를 참조로 변환하는 일도 자동으로 해준다!

객체 그래프 탐색

NOTE
객체에서 회원이 소속된 팀을 조회할 때는 참조를 사용해서 연관된 팀을 찾으면 된다. 이것을 객체 그래프 탐색이라 함
객체 연관관계 그림
객체 탐색은 member.getOrder().getOrderItem()… 와 같이 자유로운 객체 탐색이 가능해야한다
그런데 SQL을 직접 다루면 객체 그래프를 탐색할 수 있을까?
SELECT M.*, T.* FROM MEMBER M JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
SQL
복사
위와 같이 MemberDAO에서 member객체를 조회할 때 다음과 같은 SQL을 실행했다고 생각하자
회원(Member)팀(Team)에 대한 데이터는 조회가능하지만, 다른건 불가능함
SQL을 직접 다루면 처음 실행하는 SQL에 따라 객체 그래프 탐색 범위가 정해진다!
이는 테이블 조회 경우의 수마다 메소드를 만들게 되는 문제가 발생하게됨..
JPA를 통한 객체 그래프 탐색문제 해결
JPA를 사용하면 이제 자유롭게 탐색이 가능해진다
JPA는 실제 객체를 사용하는 시점까지 데이터베이스 조회를 미룬다고 해서 지연로딩(Lazy)라고 한다

JPA 비교

NOTE
데이터베이스는 기본 키의 값으로 각 row를 구분한다
객체는 동일성(identity) 비교와 동등성(equality)비교라는 2가지 방법이 존재한다
발생문제
class MemberDAO { public Member getMember(String memberId) { String sql = "SELECT * FROM MEMBER WHERE MEMBER_ID = ?"; ... // JDBC API, SQL 실행 return new Member(...); } }
Java
복사
String memberId = "010"; Member member1 = memberDao.getMember(memberId); Member member2 = memberDao.getMember(memberId); member1 == member2; //다르다
Java
복사
member1과 member2는 동일한 키로 조회한 결과이다.
테이블에서는 같은 Row에 해당한다
객체에서는 새로운 객체가 생성되었기에 다른 객체가 된다
JPA를 통한 비교 해결
JPA는 같은 트랜잭션일 떄 같은 객체가 조회되는 것을 보장한다.

JPA의 성능 최적화 기능

NOTE
1차 캐시와 동일성 보장
트랜잭션을 지원하는 쓰기 지연
지연 로딩

1차 캐시와 동일성 보장

NOTE
같은 트랜잭션 안에서는 같은 entity를 반환 → 약간의 조회 성능 향상
DB isolation Level이 Read Commit이어도 애플리케이션에서 Repetable Read 보장
String memberId = "100"; Member m1 = jpa.find(Member.class, memberId); Member m2 = jpa.find(Member.class, memberId); println(m1 == m2); // true
Java
복사
위의 코드에서 SQL은 한번만 실행된다!

트랜잭션을 지원하는 쓰기 지연 - INSERT

NOTE
트랜잭션을 commit할 때까지 INSERT SQL을 모은다
JDBC BATCH SQL 기능을 사용해서 한번에 SQL 전송
transaction.begin(); // [트랜잭션] 시작 em.persist(memberA); em.persist(memberB); em.persist(memberC); //여기까지 INSERT SQL을 데이터베이스에 보내지 않는다. //커밋하는 순간 데이터베이스에 INSERT SQL을 모아서 보낸다. transaction.commit(); // [트랜잭션] 커밋
Java
복사

지연 로딩과 즉시 로딩

NOTE
지연 로딩 : 객체가 실제 사용될 때 로딩
member를 조회 했을 떄, member만 가져온다
그리고 3번째 줄에서 team.getName을 했을 때, jpa가 db에 team에 대한 query를 날려서 가져온다.
즉시 로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회
member를 조회 했을 때, member와 연관된 객체까지 모두 가져온다
member를 가져왔을 때 member만 쓴다고 하면 지연로딩
member를 가져왔을 떄, 다른 연관 객체도 쓰는 경우 즉시로딩