JPA

왈왈왈 (Yoon tae uk)·2022년 4월 8일
0

Java Persistence API

JPA의 대해서 알아봅니다.


Goal

  • JPA 등장 배경에 대해 알아봅니다.
  • SQL 중심의 개발의 문제점을 알아봅니다.

JDBC

데이터의 세계는 10~20년 동안 급속도로 발전하였습니다. 데이터가 증가함에 따라 더 빠른 처리기술과 특수 스토리지가 발명되었습니다. 하지만 발전되는 여러 스토리지기술은 구성 및 방법, 서로 다른 API를 규격을 사용하였고 JDBC라는 기술이 등장하여 SQL 데이터 저장소의 전반적인 표준화를 제공하였습니다.

JPA

자바 개발자들은 JPA등장 이전에는 JDBC API를 사용하여 관계형 데이터베이스를 쿼리를 하였습니다. JDBC를 사용하면 기본 SQL 쿼리를 사용하였고 개발자가 SQL 문을 작성하는 것은 많은 반복과 오류가 발생하기가 쉬웠습니다. 또한 데이터베이스를 변경할 때 쿼리 구문이 변경될 가능성이 있습니다.


SQL 중심적인 개발의 문제점

무한 반복, 지루한 코드

  • 객체 CURD
public class Member {
	private Long memberId;
	private String name;
	...
}
INSERT INTO MEMBER(MEMBER_ID, NAME) VALUES
SELECT MEMBER_ID, NAME FROM MEMBER M
UPDATE MEMBER SET ...
  • 이메일 정보를 추가한다면?
    • Member 객체에 이메일 필드를 추가합니다.
    • 모든 쿼리에 이메일 정보를 추가 합니다.
    • SQL에 의존적인 개발을 피하기가 어렵습니다.
public class Member {
	private Long memberId;
	private String name;
	private String email;
	...
}
INSERT INTO MEMBER(MEMBER_ID, NAME, EMAIL) VALUES
SELECT MEMBER_ID, NAME, EMAIL FROM MEMBER M
UPDATE MEMBER SET EMAIL = ? ...

패러다임의 불일치

객체 vs 관계형 데이터베이스

  • 객체는 데이터 저장보다 ‘추상화’에 포커스가 되어있습니다.
  • 관계형 데이터베이스는 ‘데이터 관리'에 포커스가 되어있습니다.
  • 서로 다른 패러다임의 두 가지를 강제로 매핑해서 일을 처리하기 때문에 많은 작업이 필요합니다.

객체를 저장하는 다양한 저장소

  • 객체를 저장하는 저장소에는 RDB, NoSQL, File등이 있습니다.
  • 현실적으론 관계형 데이터베이스를 사용하게 됩니다.

객체를 관계형 데이터베이스에 저장

  • 객체를 SQL로 변환이 필요합니다. (개발자)
  • 너무 많은 시간이 소비됩니다.

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

1.상속

  • 객체

    • 자바는 컬렉션을 이용합니다.
    • 저장시에는 list.add(movie)로 컬렉션에 저장합니다.
    • 조회시에는 list.get(movieId)로 컬렉션에서 꺼내옵니다.
    • 간단합니다.
  • 관계형 데이터베이스

    • 저장시에는 데이터베이스에서 INSERT 쿼리를 두번 날려야합니다.
    • INSERT INTO ITEM, INSERT INTO MOVIE
    • 조회 시에는 각각의 테이블의 조인 SQL를 작성합니다.
    • 각각의 객체를 생성하여 필드에 넣어 줍니다.
    • 복잡합니다.
    • 결국 DB에 저장할 객체에는 상속관계를 사용하지 않습니다.

2.연관관계

객체

  • 객체는 참조를 사용합니다.
  • member.getTeam()처럼 참조를 합니다.
  • 멤버에서는 팀이 조회가 가능하지만 팀에서는 멤버를 조회할 수 없습니다.

테이블

  • FKPK를 조인하여 사용합니다.
  • 멤버와 팀은 N:1의 관계를 가지고 있습니다.
  • 객체와 달리 멤버에서도 팀에 조인이 가능하고 팀에서도 멤버에 조인이 가능합니다.

테이블에 맞춘 모델링

class Member{
	private String id; //MEMBER_ID 컬럼 사용
	private Long teamId; //TEAM_ID FK 컬럼 사용
	private String userName;
}
class Team{
	private Long id;//TEAM_ID PK 컬럼 사용
	private String name;
}

테이블에 맞춘 객체 저장

INSERT INTO MEMBER (MEMBER_ID, TEAM_ID, USERNAME) VALUES ...

객체다운 모델링

class Member{
	private String id; //MEMBER_ID 컬럼 사용
	private Team team; //참조로 연관관계를 맺습니다.
	private String userName;
}
class Team{
	private Long id;//TEAM_ID PK 컬럼 사용
	private String name;
}

teamId는 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

DB에서 조회후 객체에 값을 넣습니다.

  • 많은 작업이 필요합니다.
public Member find(Strubg memberId) {
  // SQL 실행하고
  Member member = new Member();
  // DB에서 조회한 회원 관련 정보를 모두 입력하고
  Team team = new Team();
  // DB에서 조회한 팀 관련 정보를 모두 넣고,

  // 회원과 팀 관계 설정
  member.setTeam(team);
  return member;
}

객체 모델링을 자바컬렉션에 관리

  • 저장시에는 멤버와 함께 팀도 같이 컬렉션에 저장을 합니다.
    • list.add(member);
  • 멤버 조회
    • Member member = list.get(memberId)
  • 팀 조회
    • Team team = member.getTeam();
  • 위에서 봤던 거와 달리 코드 한 줄로 저장, 조회를 간단하게 할 수 있습니다.
  • 하지만 DB에 넣는 순간 개발자가 중간에서 많은 일을 해야하며 생산력이 낮아집니다.

객체 그래프 탐색

객체는 자유롭게 객체 그래프를 탐색할 수 있습니다.

  • member.getTeam(), member.getOrder().getDelivery() 처럼 탐색이 가능합니다.

DB에서는 멤버와 팀, 멤버와 오더를 조회할 수 있습니다.

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

member.getTeam() //조회가능
memeber.getOrder() //SQL문의 범위에 없음

아래와 같이 엔티티 신뢰 문제가 발생합니다.

  • DAO에서 변환된 엔티티를 신뢰하고 사용할 수 없습니다.
  • 서비스와, DAO 의 계층이 물리적으로는 분리되어 있는 거 같지만, DAO 의 내부를 열어보지 않고는 엔티티 계층을 신뢰할 수 없게 됩니다.
  • 결과적으로 SQL을 직접 다루게 된다면 진정한 계층분할이 어렵게 됩니다.
class MemberService {
	...
	public void process() {
		Member member = memberDAO.find(memberId); 
		member.getTeam(); //???
		member.getOrder().getDelivery(); //???
	}
}	

0개의 댓글

관련 채용 정보