[JPA] 1. JPA 소개

김태현·2023년 10월 19일
post-thumbnail

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

DB에서는 데이터를 관리하기 위해 SQL을 사용해야 한다. Java의 경우 JDBC API를 이용하여 SQL을 DB에 전달한다.

다음과 같은 예시 상황을 살펴보자.

예시로 다음과 같이 Member객체를 만들고

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

DB관리용 DAO(데이터 접근 객체)를 만들어준다.
public class MemberDAO {
	public Member find(String memberId) {...}
    public void save(Member member) {...}
}

일반적으로 find, save기능을 구현할 때 다음과 같이 구현한다.
  1. 회원 조회용, 저장용 SQL을 작성한다.
SELECT member_id, name FROM member WHERE member_id = ?

String sql = "INSERT INTO member(member_id, name) VALUES(?, ?)";
  1. JDBC API를 사용하여 SQL을 실행한다. / 회원 객체의 값을 꺼내 등록 SQL에 전달한다.
ResultSet rs = stmt.executeQuery(sql);

pstmt.setString(1, member.getMemberId());
pstmt.setString(2, member.getName());
  1. 조회 결과를 Member 객체로 매핑한다 / JDBC API를 사용하여 SQL을 실행한다
String memberId = rs.getString("member_id");
String name = rs.getString("name");
        
Member member = new Member();
member.setMemberId(memberId);
member.setName(name);
pstmt.executeUpdate(sql);

데이터베이스는 객체 구조와 다른 데이터 중시므이 구조를 가지므로 객체를 데이터베이스에 직접 저장하거나 조회할 수 없어 SQL과 JDBC API를 사용하여 변환 작업을 해야한다. 이러한 과정은 반복적인 작업을 요구하고 많은 SQL과 JDBC API를 코드로 작성해야한다.

또한 개발과정에서 코드를 수정하는 일은 불가피하게 자주 발생하게 되는데 코드를 수정하게 될 경우 이러한 문제점과 추가 문제점 들이 발생하게된다.
요약해 보자면 애플리케이션에서 SQL을 직접 다루게 될 경우 진정한 의미의 계층 분할이 어려워지고 엔터티를 신뢰할 수 없게 되며 SLQ에 의존적인 개발을 피하기 어렵게 된다.

위 문제들은 JPA를 이용하여 해결 가능하다!
JPA를 사용하게 되면 객체를 DB에 저장하고 관리할 떄 개발자가 직접 SQL을 작성하지 않고 JPA가 제공하는 API를 사용하면 된다.



1.2 패러다임의 불일치

애플리케이션은 Java라는 객체지향 언어로 개발하고 데이터는 관계형 데이터베이스에 저장해야 한다면 패러다임의 불일치 문제를 개발자가 직접 해결해 줘야한다. 이러한 불일치 문제는 해결할 수 있지만 많은 시간과 많은 코드들이 필요하다.

첫번째로 상속이다.

우측은 객체 상속 모델이고 좌측은 테이블 모델이다. 객체는 상속이라는 기능이 있지만 테이블은 상송이라는 기능이 없다. 가장 유사하게 슈퍼타입-서브타입 관계를 사용하여 설계할 수 있다. JDBC API를 사용하여 구현할려면 갱신, 수정, 삭제 모두 쉽지 않고 번거롭다.

이러한 점을 JPA는 쉽게 해결할 수 있다. 개발자는 자바 collection에 객체를 저장하듯이 JPA에게 객체를 저장하면된다.

객체 저장의 경우 presist()메소드를 사용해서 객체를 저장한다.
객체 조희의 경우 find()메소드를 사용해서 객체를 조회한다.


두번째로 연관관계이다. 연관관계는 객체의 경우 참조를 사용해 다른 객체와 연관관계를 가지고 참조에 접근해 연관된 객체를 조회한다. 반면 테이블은 외래 키를 사용해 다른 테이블과 연관관계를 가지고 조인을 사용해서 연관된 테이블을 조회한다. 연관관계의 패러다임 불일치를 해결하기 위해서는 막대한 소모비용이 발생한다.
member.setTeam(team); //회원과 팀 관계 설정
jpa.persist(member); //회원과 연관관계 함께 저장

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

다음과 같이 JPA를 활용하여 참조를 외래키로 변환해 적절한 SQL문을 DB로 전달하며 조회 시 외래키를 참조 변환하는 일 역시 가능하다.


세번째로 객체 그래프 탐색이다. 객체는 자유롭게 객체 그래프를 탐색 할 수 있어야 하지만 SQL은 그렇지 못하다. 즉 SQL문에 의해 탐색 범위가 지정된다. 이를 해결하기 위해서는 상황에 따른 여러 DAO를 만들어주어야 한다.
member.getOrder().getOrderItem()...//자유로운 객체 그래프 탐색

JPA를 활용하면 다음과 같이 적절한 SQL문을 실행하여 자유롭게 조회할 수 있다. 이러한 위의 기능을 Lazy Loading이라고 한다.


마지막으로 비교이다.
String memeberId = "100";
Member member1 = memberDAO.getMember(memberId);
Member member2 = memberDAO.getMember(memberId);

member1 == member2; // false

Member member1 = list.get(0);
Member member2 = list.get(1);

member1 == member2; // true

DB는 기본키의 값으로 각 row를 구분하지만 객체는 동일성비교와 동등성 비교라는 두가지 비교 방법이 있다.
테이블 과 객체는 구분(비교)하는 방법에 차이가 존재한다.

🕯️동일성 비교 vs 동등성 비교

  • 동일성 비교는 == 비교 -> 객체 인스턴스의 주소 값을 비교
  • 동등성 비교는 equals() 비교 -> 객체 내부의 값을 비교
String memberId = "100";
Member member1 = jpa.find(Member.class, memberId);
Member member2 = jpa.find(Member.class, memberId);

member1 == member2; // true

JPAf를 활용하면 같은 트랜잭션일 댸 같은 객체가 조회되는 것을 보장할 수 있다.



1.3 JPA란?

1.3.1 JPA 동작

JPA는 Java진영의 ORM 기술 표준으로 아래 그림과 같이 동작한다.

🕯️ORM

  • 객체와 관계형 데이터베이스를 메핑한다는 것
  • ORM 프레임워크 사용 시 객체와 테이블을 매핑해서 페러다임의 불일치 문제를 개발자 대신 해결


객체를 저장할 경우의 동작은 다음과 같다.

jpa.persist(member);

세부적으로 살펴보면 JPA에게 Member객체를 넘기면 JPA가 객체를 분석하고 INSERT 쿼리가 생성된다(JPA가 만듬). JPA가 JDBC API를 사용하여 INSERT 쿼리를 DB에 보내게 되며 패러다임의 불일치를 해소한다.


객체를 조회할 경우의 동작은 다음과 같다.

Member member = jpa.find(memberId);

세부적으로 살펴보면 JPA에게 PK값으로 find요청을 보내고 JPA는 SELECT 쿼리를 생성한다. JPA가 JDBC API를 사용하여 DB에 보내고 결과를 받아온다. 이를 ResultSet에 매핑하여 패러다임의 불일치를 해소한다.

JPA를 사용하기 위해서는 JPA를 구현한 ORM 프레임워크를 선택해서 사용해야한다. ORM프레임워크 종류에는 하이버네이트(Hibernate), EclipseLink, DataNucleus가 있는데 하이버네이트가 가장 대중적이다.


1.3.1 JPA 사용이유

JPA를 사용하는 이유는 대표적으로 생산성, 유지보수, 패러다임의 불일치 해결, 성능, 데이터 접근 추상화와 벤더 독립성, 표준이 있다.

생산성 - CURD모두 정의되어 있다.

🕯️JPA CRUD 살펴보기
저장: jpa.persist(member)
조회: Member member = jpa.find(memberId)
수정: member.setName(“변경할 이름”)
삭제: jpa.remove(member)

유지보수 - 필드 변경시 모든 SQL 수정해야 했으나 JPA사용시 필드만 추가하면 된다.
패러다임의 불일치 해결 - 앞에 내용에서 확인해봄(상속, 연관관계, 객체 그래프탐색, 비교)
성능 - JPA는 애플리케이션과 DB사이에서 성능 최적화 기회를 제공한다.
데이터 접근 추상화와 벤더 독립성 - ??
표준 - Java의 ORM 기술 표준이다.

1개의 댓글

comment-user-thumbnail
2023년 10월 20일

유익한 글 잘 읽었습니다.🙂
오늘도 힘내세요.🙌🙌🏻🙌🏼

답글 달기