JPA 소개

2023. 4. 27. 10:24JPA

반응형

JPA의 등장

 

초기에 JDBC API를 직접 사용해서 코딩

: 애플리케이션의 비즈니스 로직보다 SQL과 JDBC API를 작성하는 데 더 많은 시간을 보냄.

MyBatis, JdbcTemplate 같은 SQL Mapper를 사용

: JDBC API 사용 코드를 많이 줄일 수 있었음.

하지만 여전히 등록, 수정, 삭제, 조회(CRUD)용 SQL을 반복해서 작성해야했음 -> 지루하고 비생산적임.

JPA는 지루하고 반복적인 CRUD SQL을 알아서 처리해줄 뿐만 아니라 객체 모델링과 관계형 데이터베이스 사이의 차이점도 해결해주었다.

객체와 관계형 데이터베이스 간의 차이를 중간에서 해결해주는 ORM(Object-Relational Mapping)프레임워크 -> JPA는 자바 진영의 ORM 기술 표준임

JPA는 개발자가 직접 SQL을 작성하는것이 아니라 JPA가 제공하는 API를 사용하면 된다. 그러면 JPA가 개발자 대신에 적절한 SQL을 생성해서 데이터베이스에 전달한다.

객체와 관계형 데이터베이스 사이의 차이점 (패러다임의 불일치)

 

<객체 연관관계>

Member 객체는 Member.team 필드에 Team객체의 참조를 보관해서 Team객체와 관계를 맺는다.

따라서 이 참조 필드에 접근하면 Member와 연관된 Team을 조회할 수 있다.

member.getTeam();

 

<테이블 연관관계>

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는 불가능하다.

반면에 테이블은 외래 키 하나로 MEMBER JOIN TEAM도 가능하지만, TEAM JOIN MEMBER도 가능하다.

 

그럼 객체를 테이블에 맞춰 모델링하면?

 

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

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

이렇게 객체를 테이블에 맞춰 모델링하면 객체를 테이블에 저장하거나 조회할 때는 편리하다.

그런데 TEAM_ID 외래키의 값을 그대로 보관하는 teamId의 필드에는 문제가 있다.

관계형 데이터베이스는 조인이라는 기능이 있으므로 외래키의 값을 그대로 보관해도 된다.

하지만 객체는 연관된 객체의 참조를 보관해야 다음처럼 참조를 통해 연관된 객체를 찾을 수 있다.

Team team = member.getTeam();

결국 Member객체와 연관된 Team객체를 참조를 통해서 조회할 수 없다. => 객체지향의 특징을 잃어버림...

객체 지향적인 방법은 참조 !!!!!!!!

 

객체지향 모델링

 

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

  Team getTeam() {
    return team;
  }
}

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

Member.team 필드를 보면 외래 키의 값을 그대로 보관하는 것이 아니라 연관된 Team의 참조를 보관한다. 이제 회원과 연관된 팀을 조회할 수 있다.

Team team = member.getTeam();

그런데 이처럼 객체지향 모델링을 사용하면 객체를 테이블에 저장하거나 조회하기가 쉽지않다. Member 객체는 team필드로 연관관계를 맺고 MEMBER 테이블은 TEAM_ID 외래 키로 연관관계를 맺기 때문인데, 객체 모델은 외래 키가 필요없고 단지 참조만 있으면 된다. 반면에 테이블은 참조가 필요 없고 외래키만 있으면 된다.

=> 결국, 개발자가 중간에서 변환 역할을 해야 한다...

=> 이런 과정들은 모두 패러다임의 불일치 문제를 해결하기 위해 소모하는 비용이다.

JPA와 연관관계

 

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

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

개발자는 회원과 팀의 연관관계를 설정하고 회원 객체를 저장하면 된다. JPA는 team의 참조를 외래 키로 변환해서 적절한 INSERT SQL을 데이터베이스에 전달한다. 객체를 조회할 때 외래 키를 참조로 변환하는 일도 JPA가 처리해준다.

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

 

왜 JPA를 사용해야 하는가?

 

생산성

INSERT SQL을 작성하고 JDBC API를 사용하는 지루하고 반복적인 일은 JPA가 대신 처리해준다.

유지보수

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

패러다임의 불일치 해결

성능

String memberId = "helloId";
Member member1 = jpa.find(memberId);
Member member2 = jpa.find(memberId);

이것은 같은 트랜잭션 안에서 같은 회원을 두 번 조회하는 코드의 일부분이다. JDBC API를 사용해서 해당 코드를 직접 작성했다면 회원을 조회할 때마다 SELECT SQL을 사용해서 데이터베이스와 두 번 통신했을 것이다. JPA를 사용하면 회원을 조회하는 SELECT SQL을 한 번만 데이터베이스에 전달하고 두 번째는 조회한 회원 객체를 재사용한다.

데이터 접근 추상화와 벤더 독립성

관계형 데이터베이스는 같은 기능도 벤더마다 사용법이 다른 경우가 많다. 단적인 예로는 페이징 처리는 데이터베이스마다 달라서 사용법을 각각 배워야한다. 결국, 애플리케이션은 처음 선택한 데이터베이스 기술에 종속되고 다른 데이터베이스로 변경하기는 매우 어렵다.

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

반응형

'JPA' 카테고리의 다른 글

연관관계 매핑 기초  (0) 2023.04.27
엔티티 매핑  (0) 2023.04.27
영속성 관리 (2)  (0) 2023.04.27
영속성 관리 (1)  (0) 2023.04.27
JPA 시작  (0) 2023.04.27