-
01-1. JPA 소개JPA 2020. 12. 1. 21:52
1.1 SQL을 직접 다룰 때 발생하는 문제점
관계형 데이터베이스는 가장 대중적이고 신뢰할 만한 안전한 데이터 저장소다.
그래서 자바로 개발하는 애플리케이션은 대부분 관계형 데이터베이스를 데이터 저장소로 사용한다.
데이터베이스에 데이터를 관리하려면 SQL을 사용해야 한다.
자바로 작성한 애플리케이션은 JDBC API를 사용해서 SQL을 데이터베이스에 전달한다.
1.1.1 반복, 반복 그리고 반복
SQL을 직접 다룰 때의 문제점을 알아보기 위해 자바와 관계형 데이터베이스를 사용해서 회원 관리 기능을 개발해보자.
회원 테이블은 이미 만들어져 있다고 가정하고 회원을 CRUD하는 기능을 개발해보자.
1. 회원 객체 만든다,
2. 회원 객체를 데이터베이스에 관리할 목적으로 회원용 DAO를 만든다.
3. 2번에서 만든 회원용 DAO이 find() 메소드를 완성해서 회원을 조회하는 기능을 개발한다.
4. 회원 조회용 SQL을 작성한다
- SELECT MEMBER_ID, •••FROM MEMBER M WHERE MEMBER_ID = ?
5. JDBC API를 사용해서 SQL을 실행한다.
- ResultSet rs = stmt.executeQuery(sql);
6. 조회 결과를 Member 객체로 매핑한다.
- String memberId = rs.getString("MEMBER_ID");
- Member member = new Member();
- member.setMemberId(memberId);
회원 조회 기능을 완성했다. 다음으로 회원 등록, 수정, 삭제 기능을 만들어보자.
그러면 위와 같은 순서대로 회원 등록, 수정, 삭제 기능을 구현해야 한다.
문제는 객체를 데이터베이스에 CRUD하려면 너무 많은 SQL과 JDBC API를 코드로 작성해야 한다는 점이다.
개발하려는 애플리케이션에서 사용하는 데이터베이스 테이블이 100개라면 무수히 많은 SQL을 작성해야 하고 이런 비슷한 일을 100번은 더 반복해야한다. 데이터 접근 계층(DAO)을 개발하는 일은 이렇듯 지루함과 반복의 연속이다.
1.1.2 SQL에 의존적인 개발
Member나 Team처럼 비즈니스 요구사항을 모델링한 객체를 엔티티라 하는데,
지금처럼 SQL에 모든 것을 의존하는 상황에서는 개발자들이 엔티티를 신뢰하고 사용할 수 없다.
대신에 DAO를 열어서 어떤 SQL이 실행되고 어떤 객체들이 함께 조회되는지 일일이 확인해야 한다.
논리적으로는 엔티티와 아주 강한 의존관계를 가지고 있다.
이런 강한 의존관계 때문에 회원을 조회할 때는 물론이고 회원 객체에 필드를 하나 추가할 때도
DAO의 CRUD 코드와 SQL 대부분을 변경해야 하는 문제가 발생한다.
1.2 패러다임의 불일치
관계형 데이터베이스는 데이터 중심으로 구조화되어 있고, 집합적인 사고를 요구한다.
그리고 객체지향에서 이야기하는 추상화, 상속, 다형성 같은 개념이 없다.
객체와 관계형 데이터베이스는 지향하는 목적이 서로 다르므로 둘의 기능과 표현 방법도 다르다.
이것을 패러다임 불일치 문제라한다. 따라서 객체 구조를 테이블 구조에 저장하는 데는 한계가 있다.
애플리케이션은 자바라는 객체지향 언어로 개발 데이터는 관계형 데이터베이스에 저장해야 한다면,
패러다임 불일치 문제를 중간에서 개발자가 해결해야 한다.
문제는 이런 객체와 관계형 데이터베이스 사이의 패러다임 불일치 문제를 해결하는 데 너무 많은 시간과 코드를 소비하는 데 있다.
1.2.1 상속
위의 그림처럼 ITEM 테이블의 DTYPE 컬럼을 사용해서 어떤 자식 테이블과 관계가 있는지 정의했다.
예를 들어 DTYPE의 값이 MOVIE이면 영화 테이블과 관계가 있다.
abstract class Item { Long id; String name; int price; } class Album extends Item { String artist; } class Movie extends Item { String director; String actor; } class Book extends Item { String author; String isbn; }
Album 객체를 저장하려면 이 객체를 분해해서 다음 두 SQL을 만들어야 한다.
INSERT INTO ITEM ...
INSERT INTO ALBUM ...
Movie 객체도 마찬가지다.
INSERT INTO ITEM ...
INSERT INTO Movie ...
JDBC API를 사용해서 이 코드를 완성하려면 부모 객체에서 부모 데이터만 꺼내 ITEM용 INSERT SQL을 작성하고 자식 객체에서 자식 데이터만 꺼내서 ALBUM용 INSERT SQL을 작성해야 할 코드량이 만만치 않다. 그리고 자식 타입에 따라서 DTYPE도 저장해야 한다.
조회하는 것도 쉬운 일은 아니다. ITEM과 ALBUM 테이블을 조인해서 조회한 다음 그 결과로 Album 객체를 생성해야 한다.
이런 과정이 모두 패러다임 불일치를 해결하려고 소모하는 비용이다.
JPA와 상속
JPA는 상속과 관련된 패러다임의 불일치 문제를 개발자 대신 해결해준다.
개발자는 마치 자바 컬렉션에 객체를 저장하듯이 JPA에게 객체를 저장하면 된다.
jpa.persist(album); //JPA는 다음 메소드를 활용하여 ITEM, ALBUM 두 테이블에 나누어 저장한다.
String albumId = "id100";
Album album = jpa.find(Album.class, albumId); //JPA는 다음 메소드를 활용하여 ITEM과 ALBUM 두 테이블을 조인해서 필요한 데이터를 조회하고 그 결과를 반환해 준다.
개발자는 따로 SQL문을 작성하지 않고 JPA에서 제공해주는 해당 메소드들을 사용하면 쉽게 조회 및 저장이 가능하다.
'JPA' 카테고리의 다른 글
02. JPA 시작 (0) 2021.01.17 01-3. JPA란 무엇인가? (0) 2021.01.14 01-2. JPA 소개 (2) 2020.12.29 Pageable 사용하기 (0) 2020.02.08 JPA란 무엇인가? (0) 2019.12.22