JPA 등장배경

JDBC > MyBatis, JDBCTemplate > JPA 순서

 

과거에는 순수 JDBC를 사용하여 객체를 DB에 저장하려면 JDBC API와 SQL를 직접 입력해야 했다

지금은 JPA를 사용하면 SQL을 작성할 필요가 없어진다.

JPA는 SQL 자동화, 수십 줄의 코드를 한 두줄로 줄일 수 있다.

 

여기서 객체와 데이터를 매핑하는 게 중요하다.

기본키와 외래키 매핑, 1:N, N:1, 1:1 , N:M

 

 

JPA 내부동작 방식과 JPA가 어떤 SQL을 만드는지 언제 실행하는지를 이해해 보자

 

객체를 관계형 DB에 관리한다.

어떻게? 수많은 SQL 쿼리로! 

 

  • SQL 중심개발의 문제점

객체 하나를 DB에 CRUD(조회, 수정, 삭제..)를 하려면 수많은 SQL을 작성해야해서 무한반복이 되기 때문에

SQL 중심적인 개발의 문제점이다

예를들어 객체 필드를 추가하면 쿼리문을 모두 수정해야하기 때문에 SQL에 의존적인 개발을 피하기 어렵다.

(JPA는 SQL을 처리해줌)

 

 

패러다임 불일치란?
객체와 DB는 목적이 다르다

객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다.

객체를 영구 보관하는 다양한 저장소들이 있다 > RDB, NoSQL, File, OODB

그 중 8~90% 는 현실적인 대안으로 관계형 데이터베이스에 저장(RDB)한다. 

 

먼저 객체를 관계형 데이터베이스에 저장하려면 어떤 순서대로?

객체 > SQL 변환 > RDB에 SQL에 전달한다 누가?  개발자가! 

즉 개발자는 SQL매퍼 일을 한다.

 

 

 

 

상속

 

다시 돌아가서 

데이터를 DB에 저장을 할 때

관계형 데이터베이스는 객체의 상속관계를 저장할 수 있을까? NO!!

부모 테이블 - 자식 테이블을 나눠 만들어서 데이터를 분리하여 필요할 땐 조인해서 들고올 수 있다

이것을 '슈퍼타입, 서브타입'이라고 한다.

 

Album 테이블을 들고오고 싶으면 ALBUM 테이블과 ITEM 테이블을 조인해서 같이 들고와서.. 각 객체 생성하고 ....

 = 조인쿼리 때문에 복잡해짐

이것을 모두 개발자가 해야하는 문제가 생겨버림

 

 

만약 자바 컬렉션에 저장한다면? 

list.add(album);

 

또는 자바 컬렉션에서 조회한다면?

Album album = list.get(albumId);

 

자바 컬렉션에 저장하는 이유는 아래에서 자세히 설명.

 

 

연관관계

객체는 참조를 사용  테이블은 외래키를 사용
member.getTeam(); JOIN ON M.TEAM_ID = T.TEAM_ID

 

member 객체와 team 객체를 데이터에 저장할때 테이블에 맞춰서 모델링을 해야한다. 

class Member {
	String id;
	Long teamId; //TEAM_ID FK 컬럼사용
	String username;
}

class Team {
	Long id; //TEAM_ID PK 컬럼사용
	String name;
}

 

 

이것보다 객체답게 모델링하는 방법은 참조의 연관관계를 맺는다.

class Member {
	String id;
	Team team; // 연관관계
	String username;
}

위와 같이 insert into Member (MEMBER_ID, TEAM_ID, USERNAME) 쿼리문을 날릴때

member 클래스에는 team에 대한 참조만 있고 teamId는 없기때문에

우선 멤버 객체에서 team을 조회하고 teamId를 가져온다.

member.getTeam().getId();

 

 

 

위처럼 member와 team을 DB에 저장하는게 아니라 자바 컬렉션에 관리를 한다면?

연관관계만 설정해두고 member만 추가를 하면 연관된 team이 컬렉션에 들어가게된다. 

list.add(member);
Member member = list.get(memberId);
Team team = member.getTeam(); 

 

**자바컬렉션에서 조회하여 두개의 인스턴스를 생성하여 값을 넣으면 비교했을때 값이 같다. 

String memberId = "123";
Member member1 = list.get(memberId);
Member member2 = list.get(memberId);
 
 member1 == member2; //같음

 

그치만 객체답게 모델링할수록 매핑작업이 늘어난다...

객체를 자바 컬렉션에 저장하듯이 DB에 저장할 수는 없을까??

 

그 문제를 해결하는게 바로 JPA 기술이다.

 

 

JPA 

Java Persistence API 

자바진영의 ORM 기술표준이다

 

ORM

Object-relational mapping 객체 관계 매핑 (객체와 관계형 DB를 매핑)

객체는 객체대로 설계

관계형 데이터베이스는 관계형 데이터베이스대로 설계

ORM 프레임워크가 중간에서 매핑

java 같은 대중적인 언어에는 ORM 기술이 존재

 

 

 

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

원래는 개발자가 JDBC API를 썼다면 이제는 JPA가 대신 쓴다

 

 

JPA 동작 (저장)

멤버 객체를 저장할때 JPA에 저장해달라고 던져주면 JPA가 회원 객체를 분석하여 INSERT SQL을 생성하고

JDBC API를 사용하여 DB에게 INSERT 쿼리문을 날려준다 중요한건 패러다임 불일치 해결

 

JPA 동작 (조회)

조회할때 JPA가 회원 객체를 분석하여 SELECT SQL 생성 JDBC API를 사용하여 ResultSet매핑,  패러다임 불일치 해결

Entity 오브젝트를 만들어서 결과를 반환해준다.

 

 

JPA는 표준명세이며 표준 인터페이스의 모음이다

표준 인터페이스를 구현한 대표적인 구현체는 하이버네이터이다 (90퍼이상 사용)

 

JPA 와 CRUD

저장 jpa.persist(member)

조회 Member member = jpa.find(memberId)

수정 member.setName("변경할 이름")

삭제 jpa.remove(member)

 

 

 

JPA 장점

- SQL 중심적인 개발에서 객체 중심으로 개발

- 생산성

저장 : jpa.persist(member)
조회 : Member member = jpa.find(memberId)
수정 : member.setName("변경할 이름")
삭제 : jpa.remove(member)

 

 

- 유지보수

  • 기존 : 필드 변경시 모든 SQL 수정을 해야함
public class Member {
	private String memberId;
	private String name;	
	private String tel; // 필드 추가
}
INSERT INTO MEMBER(MEMBER_ID, NAME, TEL) VALUES
SELECT MEMBER_ID, NAME, TEL FROM MEMBER M
UPDATE MEMBER SET... TEL = ?
  • JPA : 필드만 추가하면 된다. SQL은 JPA가 처리해줌

 

 

- 패러다임 불일치 해결

  • JPA 와 상속
  • JPA 와 연관관계
  • JPA 와  객체 그래프 탐색
  • JPA 와 비교하기

 

 

- 성능

  • 1차 캐시와 동일성 보장 (같은 트랜잭션 안에서는 같은 엔티티를 반환)

m1 > 처음에는 sq쿼리문으로 조회를 하고 (jpa가 값을 들고 있음 )

m2 > 그 다음에는 캐시에 저장된 객체를 반환 

 

*SQL은 1번만 실행하며 같은 트랜잭션안에서만 가능하다.

String memberId = "100";
Member m1 = jpa.find(Member.class, memberId); //SQL 쿼리
Member m2 = jpa.find(Member.class, memberId); //캐시(메모리상)에서 반환

printIn(m1 == m2)  // true

 

  • 네트워크 통신비용을 줄일 수 있다.
transaction.begin(); // 트랜잭션 시작

//아직까지 INSERT SQL 을 DB에 안보냄
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);

//커밋하자마자 DB의 INSERT SQL을 모아서 보낸다
transaction.commit(); // 트랜잭션 커밋

 

 

  • 지연로딩 (Lazy loading)

: 객체가 실제 사용될때 로딩

멤버를 조회할때 항상 팀도 조회가 된다면? 멤버를 조회할때 팀을 한번에 조인해서 가져오는게 네트워크 통신비용이 감소

또는 멤버만 조회를 하고싶고 연관된 팀을 안가져오고 싶을때

 

반대로 멤버와 팀을 자주 사용한다면 '즉시 로딩'이다.

 

 

- 데이터 접근 추상화와 벤더 독립성

- 표준

 

 

 

 

 

반응형
LIST

+ Recent posts