티스토리 뷰

JAVA/JPA

JPA 소개 및 특징

최진영 2021. 8. 9. 10:57

우리가 만드는 대부분의 어플리케이션은 객체 지향적인 언어를 사용한다. (Java, Scala ...)

하지만 데이터베이스에서는 아직은 RDB가 시장 대부분을 차지하고 있다. (Mysql, Oracle ...)

 

그래서 어떻게보면 객체를 RDB에 저장하여야하고 RDB에서 데이터를 꺼내서 객체에 매핑해서 사용해야한다.

즉, SQL 중심적인 개발을 진행해야한다.

 

누구나 한번쯤 느낄 수 있다. CRUD가 반복되는 무한반복 지루한 코딩

자바 객체를 SQL로, SQL를 자바객체로 변환하는 무수히 반복되는 코딩으로 인해서 SQL개발자인지 JAVA 개발자인지 분간이 되지 않는 상황이 오게 된다.

그 과정에서 겪을 수 있는 예를 보자.

객체 CRUD - 필드 추가

회원을 설계하고 회원을 저장하는 개발을 했다고 치자.

public class Member {
	private String memberID;
	private String name;
	...
}
INSERT INTO MEMBER(MEMBER_ID, NAME) VALUES
SELECT MEMBER_ID, NAME FROM MEMBER M
UPDATE MEMBER SET ...

과 같은 member객체와 member를 crud 하는 코드가 있다. 근데 여기서 필드를 추가하라고 한다. 그럼 다음과 같은 복잡한 과정이 추가가 되어야 한다.

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 = ?

연락처라는 컬럼 하나를 추가하기 위해서 너무 많은 쿼리들을 작업해야하게 되는 불상사가 일어난다.

즉, SQL에 의존적인 개발을 피할 수 없다는데에 문제가 있는 것이다.

 

 

결국 이 문제가 발생하는 근본적인 원인이 무엇일까?

객체지향적인 개발과 RDB 개발의 목적 방향성이 차이가 있다는 것이다.

객체 지향 프로그래밍은 추상화, 캡슐화, 상속, 다형성 등 시스템의 복잡성을 제어하기 쉽도록 프로그래밍을 하는 것을 말한다.

1. 상속

객체의 상속관계와 RDB의 상속관계는 전혀 다른 개념이다. pk과 fk로써의 관계가 비슷하다고 보이긴 하지만 둘은 다르게 보아야하는 개념이다.

객체지향 모델링과 RDB 모델링

Album을 저장하려면 어떻게 될까?

  1. ITEM에 insert하고
  2. ALBUM에 insert해야한다.

조회하려면?

각각의 테이블에 조인 sql을 작성해야하고 객체를 따로 생성해야하고...

즉, db와 객체 사이의 매핑으로써 crud를 하는데 있어서 무수한 복잡한 상황이 발생한다.

 

근데 생각해보니 우리가 자바 컬랙션 저장소에 저장, 조회한다고 생각하면..?

items.add(ablum);	// 추가

Album album = items.get(albumId); // 조회

Item item = items.get(albumId);	// 부모 타입으로 조회 후 다형성 활용도 가능

사실 자질구래한 매핑없이 바로바로 사용을 할 수 있다.

 

2. 연관관계


테이블 같은 경우 연관관계를 매핑할 때 PK와 FK로 연관관계를 매핑하기 때문에 어떤 테이블을 검색하든 연관관계에 있는 테이블을 검색할 수 있다.

하지만 객체 같은 경우 Member를 가지고 Team을 검색할 수 있지만 Team을 가지고는 Member를 검색할 수 있지 않다.

 

3. 객체를 테이블에 맞추어 모델링

많은 SQL지향적인 개발의 객체를 보면 다음과 같이 구성되어 있을 것이다.

class Member {
	Long id;	// MEMBER_ID PK 컬럼
  Long teamId;	// TEAM_ID FK 컬럼
  String username;
}

class Team {
  Long id;	// TEAM_ID PK 컬럼
  String name;
}
INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES ...

 

근데 사실 객체지향적인 모델링은 다음과 같이 만들 수 있다. 레퍼런스, 참조값을 가져야 객체지향적이게 될 수 있다는 말이다.

class Member {
	Long id;	// MEMBER_ID PK 컬럼
  Team team;
  String username;
    
  Team getTeam() {
    return team;
  }
}

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

그럼 사실 sql에 넣을 때 조금 문제가 있다. TEAM_ID를 넣어야하는데 참조값으로 저장되어있기 때문에 코드를 중간에 커스텀해야한다.

member.getTeam().getId();
INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES ...

 

그럼 이렇게 설계된 객체에 조회하려면 어떻게 될까?

SELECT M.*, T.*	FROM MEMBER M	JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
public Member find(String memberId) {  // sql 실행    Member member= new Member();  // member에 전부 입력  Team team = new Team();  // team에 전부 입력    // 회원과 팀관계 설정  member.setTeam(team);  return member;}

 

4. 처음 실행하는 SQL에 따라 탐색 범위 결정

SELECT M.*, T.*	FROM MEMBER T	JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID

만약 처음 실행하는 sql이 다음과 같다면

member.getTeam();	//okmember.getOrder(); //null

와 같이 Order에 member가 연관이 되어있음에도 불과하고 가지고 오지 못하는 상황이 발생한다. 결국 entity에 대한 신뢰성이 무너지게 된다는 것이다.

 

5. 객체가 다르다

String memberId = "100";Member member1 = MemberDAO.getMember(memberId);Member member2 = MemberDAO.getMember(memberId);member1 != member2;

sql에서 그때그때마다 쿼리를 날려서 받아오기 때문에 두 객체는 분명히 레퍼런스 값이 다를 수 밖에 없다. 그때그때마다 객체를 생성해서 꺼내오기 때문이다.

 

근데 컬랙션에서는 이걸 어떻게 할까?

String memberId = "100";Member member1 = list.get(memberId);Member member2 = list.get(memberId);member1 == member2;

둘은 컬랙션에서 가져왔을때 당연히 레퍼런스가 같다고 볼 수 있다.

 

결론

결국 객체답게 모델링할수록 객체와 sql간의 괴리감이 늘어나기 때문에 무수히 많은 작업이 필요하다.

그래서 나온 것이 JPA가 되겠다.

 

JPA

  • 인터페이스의 모음
  • JPA 표준 명세를 구현 3가지 구현체
  • 하이버네이트, EclipseLink, Datanute

 

결국 JPA를 사용해야하는 이유는 앞선 문제점들을 개선하고자하는 것이 JPA이기 때문이다.

  • SQL 중심적인 개발에서 객체 중심적인 개발
  • 생산성
저장 : jpa.presist(member)조회 : Member member = jpa.jind(memberId)수정 : member.setName("변경할 이름")삭제 : jpa.remove(member)

>> 자바 컬랙션처럼 db를 사용하는 개념이라고 생각하면 편함

  • 유지보수
기존 : 필드 변경 시 모든 SQL 변경컬럼 필드만 추가하면 됨
  • 패러다임 불일치 해결
JPA와 상속JPA와 연관관계
  • 성능
1차 캐시와 동일성 보장트랜잭션을 지원하는 쓰기 지연지연 로딩
  • 데이터 접근 추상화와 벤더 독립성
  • 표준

 

 

본 게시글은 김영한님의 자바 ORM 표준 JPA 프로그래밍을 정리한 글 입니다.

'JAVA > JPA' 카테고리의 다른 글

JPA 모든 N+1 발생 케이스과 해결책  (0) 2021.11.23
연관관계 매핑 기초  (0) 2021.08.12
엔티티 매핑  (0) 2021.08.10
영속성 관리 - 내부 동작 방식  (0) 2021.08.09
댓글
최근에 올라온 글
Total
Today
Yesterday