1장 JPA 소개

sua·2023년 4월 19일
0

개발자들은 객체를 단순히 테이블에 맞추어 데이터 전달 역할만 하도록 개발하는 데에 의문이 들었다 -> 객체 모델링을 적용해보았지만 세밀하게 진행할수록 객체와 관계형 데이터베이스의 차이를 메우기 위해 더 많은 SQL을 작성해야 했음!! 그리고 결과적으로는 또 객체 모델이 데이터 중심의 모델로 변해갔다고 한다. -> 이러던 중 객체와 관계형 데이터베이스 간의 차이를 중간에서 해결해주는 ORM이 나왔음. -> JPA(ORM 기술 표준)는 반복적인 CRUD SQL을 알아서 처리 + 객체 모델링과 관계형 데이터베이스 사이의 차이점도 해결해주어 객체 중심으로 개발할 수 있게 됨.

1.1 SQL을 직접 다룰 때 발생하는 문제점

데이터베이스에 데이터를 관리하려면 SQL을 사용해야 한다.
자바로 작성한 애플리케이션은 JDBC API로 SQL을 데이터베이스에 전달 -> 데이터베이스에서 결과 반환 받는 과정이 일어난다.

1.1.1 반복, 반복 그리고 반복

자바와 관계형 데이터베이스를 사용해서 회원 관리 기능을 개발해보겠다. 이 과정에서 SQL을 직접 다룰 때의 문제점을 알아볼 수 있다! 여기서 회원 테이블은 이미 만들어져 있다고 가졍하고 CRUD 기능을 개발할 것이다.

R(조회)

먼저 자바에서 사용할 회원(Member) 객체를 만들어보자.

public class Member {
	private String memberId;
    private String name;
    ...
}

회원 클래스 안에 memberId와 name이 필드로 있는 것을 알 수 있다.

다음으로 회원 객체를 데이터베이스에 관리하기 위해 데이터 접근 객체인 회원용 DAO를 만들어보자.

public class MemberDAO {
	public Member find(String memberId) {...}
}

해당 코드는 memberId로 Member 객체를 찾는 find 메소드가 정의된 MemberDAO 클래스를 작성하였다.

이제 MemberDAO의 find() 메소드를 완성해서 회원을 조회하는 기능을 개발해보자.
순서는 다음과 같을 것이다.

  1. 회원 조회용 SQL을 작성한다.
SELECT MEMBER_ID, NAME FROM MEMBER M WHERE MEMBER_ID = ?
  1. JDBC API를 사용해서 SQL을 실행한다.
ResultSet rs = stmt.executeQuery(sql);
  1. 조회 결과를 Member 객체로 매핑한다.
String memberId = rs.getString("MEMBER_ID");
String name = rs.getString("NAME");

Member member = new Member();
member.setMemberId(memberId);
member.setName(name);
...

C(등록)

public class MemberDAO {
	public Member find(String memberId) {...}
    public void save(Member member) {...} //추가
}
  1. 회원 등록용 SQL을 작성한다.
String sql = "INSERT INTO MEMBER(MEMBER_ID, NAME) VALUES(?,?)";
  1. 회원 객체의 값을 꺼내서 등록 SQL에 전달한다
pstmt.setString(1, member.getMemberId());
pstmt.setString(2, member.getName());
  1. JDBC API를 사용해서 SQL을 실행한다.
pstmt.executeUpdate(sql);

회원 객체를 데이터베이스가 아닌 자바 컬렉션에 보관한다면 어떨까?

list.add(member);

다음 한 줄로 객체를 저장할 수 있다.
하지만, 데이터베이스는 객체 구조와는 다른 데이터 중심의 구조를 가지므로 -> 객체를 데이터베이스에 직접 저장하거나 조회할 수는 없다. -> 너무 많은 코드를 작성해야 한다..


1.1.2 SQL에 의존적인 개발

앞서 개발한 기능에서 회원 연락처도 함께 저장해달라는 요구사항이 추가되었다고 가정해보자.
그렇기 때문에 등록 코드를 변경해야 한다.

등록 코드 변경

  1. 회원 테이블에 TEL 컬럼을 추가하고 회원 객체에 tel 필드를 추가한다.
public class Member {
	private String memberId;
    private String name;
    private String tel; // 추가
}
  1. 연락처를 저장할 수 있도록 INSERT SQL을 수정한다.
String sql = "INSERT INTO MEMBER(MEMBER_ID, NAME, TEL) VALUES(?,?,?)";
  1. 회원 객체의 연락처 값을 꺼내서 등록 SQL에 전달한다.
pstmt.setString(3, member.getTel());

조회 코드 변경

  1. 회원 조회용 SQL을 수정한다.
SELECT MEMBER_ID, NAME, TEL FROM MEMBER M WHERE MEMBER_ID = ?
  1. 연락처의 조회 결과를 Member 객체에 추가로 매핑
...
String tel = rs.getString("TEL");
member.setTel(tel); // 추가

문제점을 정리해보자.
Member 객체가 연관된 Tem 객체를 사용할 수 있을지 없을지는 전적으로 사용하는 SQL에 달려있다. -> 데이터 접근 계층을 사용해서 SQL을 숨겨도 DAO를 열어서 어떤 SQL이 실행되는지 확인해야 한다. -> 엔티티(Member나 Team처럼 요구사항을 모델링한 객체)를 신뢰하고 사용할 수 없는 문제가 생긴다.

요약하자면

  • 진정한 의미의 계층 분할이 어렵다.(데이터 접근 계층에 SQL과 JDBC API를 숨겨도 DAO를 열어서 어떤 SQL이 실행되는지 확인해야 함)
  • 엔티티를 신뢰할 수 없다.(SQL에 모든 것을 의존하고 있기 때문에)
  • SQL에 의존적인 개발을 피하기 어렵다.

1.1.3 JPA와 문제 해결

JPA가 문제를 어떻게 해결하는지 간단히 알아보자.
JPA를 사용하면 객체를 데이터베이스에 저장하고 관리할 때 개발자가 직접 SQL을 작성(X) JPA가 제공하는 API를 사용(O) -> JPA가 적절한 SQL을 생성해서 데이터베이스에 전달.

JPA가 제공하는 CRUD API를 간단히 알아보자.

저장 기능

jpa.persist(member); // 저장

persist() 메소드 : 객체를 데이터베이스에 저장. JPA가 객체와 매핑 정보를 보고 적절한 INSERT SQL을 생성해서 데이터베이스에 전달.

조회 기능

String memberId= "helloId";
Member member = jpa.find(Member.class, memberId); // 조회

find() 메소드 : 객체 하나를 데이터베이스에서 조회. JPA는 객체와 매핑 정보를 보고 적절한 SELECT SQL을 생성해서 데이터베이스에 전달 + 그 결과로 Member 객체를 생성해서 반환.

수정 기능

Member member = jpa.find(Member.class, memberId);
member.setName("이름변경"); // 수정

JPA는 별도의 수정 메소드를 제공하지 않는다! 대신에 객체의 값을 변경하면 트랜잭션을 커밋할 때 데이터베이스에 적절한 UPDATE SQL이 전달된다.

연관된 객체 조회

Member member = jpa.find(Member.class, memberId);
Team team = member.getTeam(); // 연관된 객체 조회

JPA는 연관된 객체를 사용하는 시점에 적절한 SELCT SQL을 실행한다. -> JPA를 사용하면 연관된 객체를 마음껏 조회할 수 있다!


1절 감상 : JPA가 단순히 편리하게 해준다고만 알고 있었는데 실제로 JPA가 없을 때는 요구사항이 조금만 변경된다고 해도 SQL을 확인해보며 일일이 다 고쳐야 했었는데 JPA를 사용하면서 그런 부분에 대해 신경을 쓰지 않고 비즈니스 로직에 더 시간을 할애할 수 있게 되었다는 점이 좋은 것 같다.



1.2 패러다임의 불일치

관계형 데이터베이스는 데이터 중심으로 구조화 -> 집합적인 사고를 요구
객체지향은 추상화, 상속, 다형성
=> 지향하는 목적이 서로 달라서 둘의 기능과 표현 방법도 다르다. (== 패러다임 불일치 문제)

1.2.1 상속

객체는 상속이라는 기능을 가지고 있지만, 테이블은 상속이라는 기능이 없음(상속 기능을 지원하지만 객체의 상속과는 다르다)

슈퍼타입 서브타입 관계 사용 -> 객체 상속과 가장 유사한 형태로 테이블 설계 가능

테이블 모델을 보면 ITEM 테이블의 DTYPE 컬럼을 사용해서 어떤 자식 테이블과 관계가 있는지 정의하였다. ex) DTYPE의 값이 MOVIE이면 영화 테이블과 관계 있다.

객체 모델 코드

abstract class Item {
	Long id;
    String name;
    int price;
}

class Album extends Item {
	String artis;
}

class Movie extends Item {
	String director;
    String actor;
}

class Book extends Item {
	String author;
    String isbn;
}

Album 객체를 예를 들면 이 객체를 저장하기 위해 객체를 분해해서 두개의 SQL을 만들어야 함

INSERT INTO ITEM ...
INSERT INTO ALBUM ...

이를 JDBC API를 사용해서 코드를 완성하려면 부모 데이터만 꺼내서 ITEM용 INSERT SQL을 작성 + 자식 데이터만 꺼내서 ALBUM용 INSERT SQL 작성 + 자식 타입에 따라서 DTYPE도 저장 => 코드량이 만만치 않다.

조회하는 경우에도 Album을 조회한다면 ITEM과 ALBUM 테이블을 조인해서 조회 -> 그 결과로 Album 객체를 생성

=> 이러한 과정 모두 패러다임의 불일치를 해결하기 위해 소모하는 비용

해당 객체들을 데이터베이스가 아니라 자바 컬렉션에 보관한다면 아주 간편해진다.

list.add(album);
list.add(movie);
Album album = list.get(albumId);

JPA와 상속

JPA는 상속과 관련된 패러다임의 불일치 문제를 개발자 대신 해결해준다.
개발자는 자바 컬렉션에 객체를 저장하듯이 JPA에게 객체를 저장하면 된다.

[JPA 사용해서 Item을 상속한 Album 객체를 저장]

  1. persist() 메소드를 사용해서 객체를 저장
jpa.persist(album);
  1. JPA는 다음 SQL을 실행해서 객체를 ITEM, ALBUM 두 테이블에 나누어 저장
INSERT INTO ITEM ...
INSERT INTO ALBUM ...

[JPA 사용해서 Album 객체 조회]

  1. find() 메소드를 사용해서 객체를 조회
String albumID = "id100";
Album album = jpa.find(Album.class, albumId);
  1. JPA는 ITEM과 ALBUM 두 테이블을 조인해서 필요한 데이터를 조회하고 그 결과를 반환
SELCT I.*, A.*
FROM ITEM I
JOIN ALBUM A ON I.ITEM_ID = A.ITEM_ID

1.2.2 연관관계

객체는 참조를 사용해서 다른 객체와 연관관계를 가지고 참조에 접근해서 연관된 객체를 조회한다.
but,
테이블은 외래 키를 사용해서 다른 테이블과 연관관계를 가지고 조인을 사용해서 연관된 테이블을 조회한다.
이러한 패러다임 불일치는 객체지향 모델링을 거의 포기하게 만들 정도로 극복하기 어렵다.

예시를 보면서 문제점을 파악해보자.

Member 객체는 Member.team 필드에 Team 객체의 참조를 보관해서 Team 객체와 관계를 맺는다. -> 참조 필드에 접근하면 Member와 연관된 Team을 조회할 수 있다.

class Member {
    Team team;
    ...
    Team getTeam() {
        return team;
    }
}

class Team {
    ...
}

member.getTeam(); // member -> team 접근

MEMBER 테이블은 MEMBER.TEAM_ID 외래 키 컬럼을 사용해서 TEAM 테이브과 관계를 맺는다. -> 외래 키를 사용해서 MEMBER 테이블과 TEAM 테이블을 조인하면 MEMBER 테이블과 연관된 TEAM 테이블을 조회할 수 있다.

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

객체참조가 있는 방향으로만 조회할 수 있다. 예제에서는 member.getTeam()은 가능하지만 team.getMember()는 참조가 없으므로 불가능하다!!
but,
테이블은 외래 키 하나로 MEMBER JOIN TEAM도 가능하지만 TEAM JOIN MEMBER도 가능하다.

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

객체를 단순히 테이블에 맞추어 모델링해보자. 이를 통해 객체와 테이블의 차이를 알아볼 것이다.

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

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

코드를 보면 MEMBER 테이블의 컬럼을 그대로 가져와서 Member 클래스를 만들었다. 이렇게 되면 객체를 테이블에 저장하거나 조회할 때는 편리하다.
but, TEAM_ID 외래 키의 값을 그대로 보관하는 teamId 필드에는 문제가 있다.
객체는 연관된 객체의 참조를 보관해야 다음처럼 참조를 통해 연관된 객체를 찾을 수 있다.

Team team = member.getTeam();

-> 외래키를 사용하는 방식으로 하면 Team 객체를 참조를 통해서 조회할 수 없게 된다. 결국 객체 지향의 특징을 잃어버리게 된다,,

객체지향 모델링

객체는 참조를 통해서 관계를 맺는다. 따라서 아래 코드와 같이 참조를 사용하도록 모델링 해야 한다.

class Member {
    String id; // MEMBER_ID 컬럼 사용
    Team team; // 참조로 연관관계를 맺는다.
    String username; // USERNAME 컬럼 사용

    Team getTeam() {
        return team;
    }
}

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

Member.team 필드는 외래 키의 값이 아니라 연관된 Team의 참조를 보관하기 때문에 회원과 연관된 팀을 조회할 수 있다.

Team team = member.getTeam();

but, 객체지향 모델링을 사용하면 객체를 테이블에 저장하거나 조회하기가 쉽지 않다.
Member 객체는 team 필드로 연관관계를 맺고 MEMBER 테이블은 TEAM_ID 외래키로 연관관계를 맺기 때문. -> 객체 모델은 외래 키가 필요 x 참조 o, 테이블은 참조 x 외래 키 o
=> 결국 개발자가 중간에서 변환 역할을 해야 함

저장

객체를 데이터베이스에 저장하려면 team 필드를 TEAM_ID 외래 키 값으로 변환해야 한다.
외래 키 값을 TEAM 테이블의 기본키이므로 member.getTeam().getId()로 구할 수 있다.

member.getId(); // MEMBER_ID PK에 저장
member.getTeam().getId(); // TEAM_ID FK에 저장
member.getUsername(); // USERNAME 컬럼에 저장

조회

조회할 때는 TEAM_ID 외래키 값을 Member 객체의 team 참조로 변환해서 객체에 보관해야 한다.
1. MEMBER와 TEAM을 조회하는 SQL

SELECT M.*, T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
  1. SQL의 결과로 아래 코드와 같이 객체를 생성하고 연관관계를 설정해서 반환
public Member find(String memberId) {
    // SQL 실행
    ...
    Member member = new Member();
    ...

    // 데이터베이스에서 조회한 회원 관련 정보를 모두 입력
    Team team = new Team();
    ...
    // 데이터베이스에서 조회한 팀 관련 정보를 모두 입력

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

이런 과정들은 모두 패러다임 불일치를 해결하려고 소모하는 비용이다. 자바 컬렉션에 회원 객체를 저장한다면 이런 비용이 전혀 들지 않는다.

JPA와 연관관계

JPA는 연관관계와 관련된 패러다임 불일치 문제를 해결해준다.

member.setTeam(team); // 회원과 팀 연관관계 설정
jpa.persist(member); // 회원과 연관관계 함께 저장

위 코드와 같이 개발자는 회원과 팀의 관계를 설정하고 회원 객체를 저장하면 된다.
JPA는 team의 참조를 외래 키로 변환해서 적잘한 INSERT SQL을 데이터베이스에 전달한다.

객체를 조회할 때 외래키를 참조로 변환하는 일도 JPA가 처리해준다

Member member = jpa.find(Member.class, memberId);
Team team = member.getTeam();

1.2.3 객체 그래프 탐색

객체에서 회원이 소속된 팀을 조회할 때는 아래 코드처럼 참조를 사용해서 연관된 팀을 찾으면 되는데 이를 객체 그래프 탐색이라고 한다.

Team team = member.getTeam(); 

객체 연관관계가 아래 그림과 같이 설계되어 있다고 가정해보자.

아래는 객체 크래프를 탐색하는 코드다.

member.getOrder().getOrderItem()... // 자유로운 객체 그래프 탐색

객체는 마음껏 객체 그래프를 탐색할 수 있어야하지만 그럴 수 있을까?
예를 들어 MemberDAO에서 member 객체를 조회할 때 이런 SQL을 실행했다면

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

회원과 팀에 대한 데이터만 조회했기 때문에 member.getTeam()은 성공하지만 다른 객체 그래프는 데이터가 없으므로 탐색할 수 없다.

member.getOrdeR(); // null

SQL을 직접 다루면 처음 실행하는 SQL에 따라 객체 그래프를 어디까지 탐색할 수 있는지 정해진다.
-> 비즈니스 로직에 따라 사용하는 객체 그래프가 다른데 언제 끊어질지 모를 객체 그래프를 함부로 탐색할 수는 없어서 개발자에겐 큰 제약이 된다.

아래 코드를 보자. (회원 조회 비즈니스 로직)

class MemberService {
    ...
    public void process() {
        Member member = memberDAO.find(memberId);
        member.getTeam(); // member -> team 객체 그래프 탐색이 가능한가?
        member.getOrder().getDelivery(); // ???
    }
}

MemberService는 memberDAO를 통해서 member 객체를 조회했지만, 이 객체와 연관된 Team, Order, Delivery 방향으로 객체 그래프를 탐색할 수 있을지 없을지는 코드만 봐서는 예측할 수 없다.
-> 어디까지 가능한지 보려면 데이터 접근 계층인 DAO를 열어서 SQL을 직접 확인해야 한다.
-> 엔티티가 SQL에 논리적으로 종속되어서 발생하는 문제!
결국 MemberDAO에 회원을 조회하는 메소드를 아래 코드처럼 상황에 따라 여러 벌 만들어서 사용해야 한다.

memberDAO.getMember(); // Member만 조회
memberDAO.getMemberWithTeam(); // Member와 Team 조회
memberDAO.getMemberWithOrderWithDelivery(); // Member와 Order와 Delivery 조회

JPA와 객체 그래프 탐색

JPA를 사용하면 객체 그래프를 마음껏 탐색할 수 있다.
JPA는 연관된 객체를 사용하는 시점에 적절한 SELECT SQL을 실행한다.
-> 연관된 객체를 신뢰하고 마음껏 조회할 수 있다.
이 기능은 실제 객체를 사용하는 시점까지 데이터베이스 조회를 미룬다고 해서 지연 로딩이라고 한다.
지연로딩을 사용하기 위해서 객체에 JPA와 관련된 어떤 코드도 직접 사용하지 않아도 된다.

아래는 지연 로딩을 사용하는 코드다.

// 처음 조회 시점에 SELECT MEMBER SQL
Member member = jpa.find(Member.class, memberId);

Order order = member.getOrder();
order.getOrderDate(); // Order를 사용하는 시점에 SELECT ORDER SQL

Member를 사용할 때 마다 Order를 함께 사용하면, 한 테이블씩 조회하는 것 보다는 Member를 조회하는 시점에 SQL 조인을 사용해서 Member와 Order를 함께 조회하는 것이 효과적이다.
JPA는 연관된 객체를 즉시 함께 조회할지 아니면 실제 사용되는 시점에 지연해서 조회할지를 간단한 설정으로 정의할 수 있다.


1.2.4 비교

데이터베이스는 기본키의 값으로 각 row를 구분.
but,
객체는 동일성 비교동등성 비교라는 두가지 비교 방법이 있음.

  • 동일성 비교 : == 비교. 객체 인스턴스의 주소 값을 비교.
  • 동등성 비교 : equals() 메소드 사용해서 객체 내부의 값을 비교.

그렇기 때문에 테이블의 로우를 구분하는 방법과 객체를 구분하는 방법에는 차이가 있다.

class MemberDAO {
    public Member getMember(String memberId) {
        String sql = "SELECT * FROM MEMBER WHERE MEMBER_ID = ?";
        ...
        // JDBC API, SQL 실행
        return new Member(...);
    }
}

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

memberId == member2; // 다르다

위 코드를 보면 기본 키 값이 같은 회원 객체를 두 번 조회했다.
그런데 둘을 동일성(==) 비교하면 false가 반환된다.
그 이유는 member1과 member2는 같은 데이터베이스 로우에서 조회했지만, 객체 측면에서 볼때 둘은 다른 인스턴스이기 때문이다.(getMember 메소드를 보면 new Meber()로 인스턴스가 새로 생성된다)
따라서 데이터베이스의 같은 로우를 조회했지만 객체의 동일성 비교에는 실패한다.
만약, 컬렉션에 보관했다면 다음과 같이 동일성 비교에 성공했을 것이다.

Member member1 = list.get(0);
Member member2 = list.get(0);
memberId == member2; // 같다

이런 패러다임의 불일치 문제를 해결하기 위해 데이터베이스의 같은 로우를 조회할 때 마다 같은 인스턴스를 반환하도록 구현하는 것은 쉽지 않다.

JPA와 비교

JPA는 같은 트랜잭션일 때 같은 객체가 조회되는 것을 보장한다.

String memberId = "100";
Member member1 = jpa.find(Member.class, memberId);
Member member2 = jpa.find(Member.class, memberId);

memberId == member2; // 같다

그러므로 위 코드에서 동일성 비교에 성공한다.


1.2.5 정리

정교한 객체 모델링을 할수록 관계형 데이터베이스 모델과의 패러다임 불일치 문제거 더 커진다. 그리고 이 틈을 메우기 위해 개발자가 소모하는 비용도 점점 많아진다. 이를 해결하기 위해 JPA가 나왔고 JPA는 패러다임의 불일치 문제를 해결해주고 정교한 객체 모델링을 유지하게 도와준다.!!

(느낀점)
배우면 배울수록 JPA는 정말.. 좋은 기술같다😂😂


1.3 JPA란 무엇인가?

JPA는 자바 진영의 ORM 기술 표준이다. JPA는 애플리케이션과 JDBC 사이에서 동작한다.

ORM은 이름 그대로 객체와 관계형 데이터베이스를 매핑한다는 뜻이다. ORM 프레임워크는 객체와 테이블을 매핑해서 패러다임의 불일치 문제를 개발자 대신 해결해준다.
ORM 프레임워크를 사용하면 객체를 데이터베이스에 저장할 때 INSERT SQL을 직접 작성하는 것이 아니라 객체를 마치 자바 컬렉션에 저장하듯이 ORM 프레임워크에 저장하면 된다. 그러면 ORM 프레임워크가 적절한 INSERT SQL을 생성해서 데이터베이스에 객체를 저장해준다.

[JPA를 사용해서 객체를 저장]

MemberDAO에서 persist 메소드를 통해 Entity Object를 저장하려고 하면 JPA는 해당 Entity를 분석한 뒤 INSERT SQL을 생성하고 JDBC API를 사용하여 데이터베이스에 객체를 저장시켜 주어 패러다임의 불일치를 해결해준다.

[JPA를 통해 객체 조회]

MemberDAO에서 find 메소드를 통해 id에 해당하는 객체를 조회하려고 하면 JPA는 SELECT SQL을 생성해서 JDBC API를 사용하여 데이터베이스에 결과를 반환 받고 ResultSet으로 매핑시켜서 Entity Object를 반환해주어 패러다임 불일치를 해결해준다.


많은 ORM 프레임워크 중에 하이버네이트가 대부분의 패러다임 불일치 문제를 해결해주는 성숙한 ORM 프레임워크다.


1.3.1 JPA 소개

JPA는 하이버네이트 기반의 자바 ORM 기술 표준이다. 즉, 자바 ORM 기술에 대한 API 표준 명세이다. -> JPA를 사용하려면 JPA를 구현한 ORM 프레임워크를 선택해야 한다.


1.3.2 왜 JPA를 사용해야 하는가?

  1. 생산성
    SQL을 작성하고 JDBC API를 사용하는 지루하고 반복적인 일을 JPA가 대신 처리해주어 생산성을 높여준다.

  2. 유지보수
    SQL을 직접 다루면 엔티티에 필드를 하나만 추가해도 관련된 등록, 수정, 조회 SQL과 결과를 매핑하기 위한 JDBC API 코드를 모두 변경해야 하지만 JPA를 사용하면 이를 대신 처리해주므로 유지보수해야 하는 코드 수가 줄어든다.

  3. 패러다임의 불일치 해결
    JPA는 상속, 연관관계, 객체 그래프 탐색, 비교하기와 같은 패러다임의 불일치 문제를 해결해준다.

  4. 성능
    JPA는 애플리케이션과 데이터베이스 사이에서 다양한 성능 최적화 기회를 제공한다.

  5. 데이터 접근 추상화와 벤더 독립성
    JPA는 애플리케이션과 데이터베이스 사이에 추상화된 데이터 접근 계층을 제공해서 애플리케이션이 특정 데이터베이스 기술에 종속되지 않도록 한다. 데이터베이스를 변경하면 JPA에게 다른 데이터베이스를 사용한다고 알려주기만 하면 된다.

  6. 표준
    JPA는 자바 진영의 ORM 기술 표준이기 때문에 다른 구현 기술로 손쉽게 변경할 수 있다.


1.4 정리

해당 장에서는 SQL을 직접 다룰 때 발생하는 다양한 문제와 객체지향 언어와 관계형 데이터베이스 사이의 패러다임 불일치 문제를 알아보았다. 그리고 이러한 점들을 JPA가 어떻게 해결하는지 알아보았다. 그리고 이런 JPA가 무엇이고 JPA의 장점들은 무엇이 있는지도 알아보았다.

profile
가보자고

0개의 댓글