백엔드/JPA

[JPA] [1] JPA 소개 - SQL 중심적 개발의 문제점

RE-Heat 2023. 8. 3. 18:46

https://www.inflearn.com/course/ORM-JPA-Basic

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

초급자를 위해 준비한 [웹 개발, 백엔드] 강의입니다. JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자

www.inflearn.com

 

인프런 김영한 님의 강의를 듣고 작성한 글입니다.

 

SQL 중심 개발의 문제점

객체 지향 언어 + 관계형 데이터베이스가 대세. 이런 식의 개발은 '객체'를 '관계형 DB'에 저장하는 양상을 띠고 있다. 

다만 이런 방식은 SQL 의존적인 개발을 불가피하게 만든다.

 

 

예를 들어 객체에 tel이라는 필드가 추가되면 Member 클래스를 다루고 있는 모든 쿼리문을 수정해야 하는 번거로움이 발생한다. 

 

객체를 SQL로 변환하는 과정. 개발자가 사실상 SQL 매퍼 역할을 맡게 된다.

 

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

 

■ 상속

객체지향 언어의 상속뿐만 아니라 추상화, 다형성 개념이 관계형 데이터베이스엔 없다.

 

객체와 DB의 구성이 비슷해 보이나 실제 언어 작동에서 차이가 난다.

 

SQL

1] Album 저장

① 객체를 분해한다 → ② 분해 후 INSERT문 수행 (INSERT INTO ITEM...) → ③ ALBUM INSERT문도 수행

2] Album 조회

① 각각 테이블에 따른 조인 SQL을 작성 → ② 각각 객체 생성 등

 

자바

1] Album 저장

list.add(album);

2] 자바 컬렉션에서 조회하는 법

Album album = list.get(albumId);

 

부모 타입으로 조회 후 다형성도 활용가능

Item item = list.get(albumId);

 

■ 연관관계

 

객체 : 참조를 사용 member.getTeam()

관계형 데이터베이스 : 외래키를 사용한다. JOIN ON M.TEAM_ID = T.TEAM_ID

 

객체 연관관계에서 Member에서 Team을 참조할 수 있으나 Team에선 참조 불가하다. 반면 테이블에선 key를 이용해 서로를 참조할 수 있다.

 

객체를 테이블에 맞춰 모델링은 한다면?

Member 클래스에 teamId를 선언해 연관관계를 설정.

 

하지만 단순한 key값이 아니라 객체 참조값이 객체 지향 설계에 더 알맞다. 그에 맞게 객체를 설계하면 아래와 같이 설계할 수 있다.

참조로 연관관계를 맺는다면 TEAM_ID는 member.getTeam().getId()로 호출할 수 있다.

 

조회는 훨씬 복잡하다.

 

 

SQL에선 JOIN을 통해 Member와 Team을 조회한다. 하지만 이를 코드로 만들려면 Member 객체를 생성한 후 정보를 입력하고 Team도 생성 후 모든 정보를 입력하는 절차를 거쳐야 한다. 이후 회원과 팀의 관계를 설정한 뒤 member를 리턴해줘야 작업이 완료된다.

 

반면 위에서 봤듯이 자바 컬렉션에선

① list.add(member);로 저장하고 

② Member와 Team 조회도

Member member = list.get(memberId)

Team team = member.getTeam();으로 간단히 수행할 수 있다. 

 

■ 객체 그래프 탐색

객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다.

 

그러나 처음 실행하는 SQL에 따라 탐색 범위가 결정돼 버린다. 

Member와 Team 그리고 Order가 연결됐지만, SQL은 Order에 대한 조회를 하지 않았으므로 nul이 뜬다.

 

 

이러면 엔티티 신뢰 문제가 발생한다. 직접 코드를 확인하기 전엔 어떤 값이 올지 확신하기 어렵다.

 

그렇다고 SQL문으로 연관된 모든 것을 조회하게 하려면 수많은 조인을 해야 하고, 이는 성능 저하를 불러일으킨다. 

 

 

그래서 과거엔 조회 메서드를 여러 개 생성했다. 이런 방법으로 어떻게든 해결할 순 있지만, 복잡한 코드가 쓰여 진정한 의미의 계층 분할이 어렵게 된다.

 

■ 비교하기

같은 memberId로 조회해도 결괏값은 '다르다'가 나온다. 왜냐면 JDBC API를 통해 새로운 Memebr 인스턴스를 생성하기 때문이다.

 

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

반면 자바 컬렉션에선 같은 값이 나오게 된다.

 

결과적으로 객체 지향적으로 모델링할수록 매핑작업이 어마어마하게 늘어난다.

 

그렇다면 객체를 자바 컬렉션에 저장하듯 DB에 저장할 순 없을까? 자바 진영에선 이러한 고민 끝에 JPA를 만들고 사용하게 된다.