BACK/JPA

[JPA] TIL 3일차 - JPA 소개

연듀 2024. 3. 30. 20:21

 

JPA 소개

 

과거에는 객체를 데이터베이스에 저장, 조회 하려면 복잡한 JDBC API와 SQL을 직접 작성해야 했다.

JdbcTemplate이나 Mybatis 같은 sql mapper 가 등장해 개발 코드는 많이 줄었지만,

sql은 직접 다 작성을 해야 했다.

JPA를 사용하면 SQL을 작성할 필요가 없다. 자바 컬렉션에 객체를 저장하고 조회하는 것처럼 단순하게 JPA를 사용한다.

JPA가 개발자 대신에 적절한 SQL을 생성하고, 데이터베이스에 실행을 해 객체를 저장하거나 불러온다.

 

JDBC → MyBatis, JdbcTemplate → JPA

 

*JDBC: Java 프로그램이 데이터베이스와 통신할 수 있도록 해주는 Java API

*MyBatis: SQL 쿼리와 Java 객체 간의 매핑을 쉽게 할 수 있도록 도와주는 SQL 매핑 프레임워크

*JdbcTemplate: Spring Framework에서 제공하는 JDBC의 간단한 추상화 계층

*JPA: Java에서 객체 관계 매핑(ORM)을 위한 API

 

 

SQL 중심적인 개발의 문제점

 

  • 객체를 DB에 CRUD하려면 반복적인 sql 코드를 작성해야 한다.
  • 객체에 필드가 추가되면 모든 sql 쿼리를 수정해야 한다.

SQL에 의존적인 개발을 피하기는 어렵다.

 

객체를 영구 보관하는 다양한 저장소(RDB, NoSQL, File, OODB..)중에 90% 정도는 관계형 데이터베이스를 쓴다.

객체를 관계형 데이터베이스에 저장 하려면, 객체에 대한 데이터를 sql로 바꿔 RDB에 전달해야 한다.

결국 개발자가 SQL 매퍼(객체와 RDB사이를 매핑)를 사용해서 해야 한다.

객체와 관계형 데이터베이스의 차이에는 크게 네가지의 차이점이 있다.

 

 

1. 상속

  • 관계형 데이터베이스에는 상속관계란 없다.
  • 슈퍼타입 서브타입 관계를 사용해 자식, 부모 처럼 테이블을 만들어야 한다.

만약 Album을 저장을 하려면 자식인 Album과 부모인 Item 두 테이블에 각각 쿼리를 날려야 한다.

조회를 할 때도 각각의 테이블에 따른 join SQL을 작성해야 한다.

그리고 각각의 객체를 또 만들고, 데이터를 넣어야 한다.

 

만약 자바 컬렉션이라면? list.add(album) 만 하면 된다.

부모 타입으로 조회해서 다형성을 활용 하는 것도 가능해진다.

Item item = list.get(albumId);

 

 

2. 연관관계

  • 객체는 참조를 사용한다.
  • 테이블은 외래키를 사용한다.

테이블에 맞춰 객체에 외래키를 저장하고, 테이블을 저장할 때 외래키를 넣는 방식으로 한다면, 

이건 객체 다운 모델링이 아니다.

객체 다운 모델링으로 참조로 연관관계를 맺게 되면, 데이터베이스에 키를 넣어 insert하기가 까다로워진다.

조회할 때 두 테이블을 조인해 가져오고, sql 실행 후 각각의 객체를 만들어 데이터 세팅하고 다시 member.setTeam(team)으로 멤버와 팀의 관계를 세팅 해줘야 한다. 정말 번거롭다.

 

자바 컬렉션에서 관리한다면?

list.add(member); 
Member member = list.get(memberId);
Team team = member.getTeam(); 

매우 편리하다.

 

 

3. 객체 그래프 탐색

 

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

그런데 데이터베이스에 데이터를 객체로 저장하면, 어떤 sql을 실행해서 이 멤버 객체를 만들었냐에 따라 탐색 범위가 결정되어 버린다.

member와 team을 조인해 가져오는 쿼리를 작성하고, getOrder()를 하려하면 null 로 조회되는 것이다.

엔티티 신뢰 문제 - DAO에서 코드를 어떻게 짰느냐에 따라 조회 범위가 달라지는 것이다.

그렇다고 모든 객체를 미리 다 로딩할 수는 없다. DAO에 상황에 따른 모든 메서드를 작성해야 한다.

→ 진정한 의미의 계층 분할이 어렵다.

= 물리적으로는 분할 되어있지만 논리적으로는 그렇지 못하다

 

 

4. 비교하기

 

sql 조회후 데이터를 다 넣은 새로운 객체를 만들면, 똑같은 아이디로 두번 조회해도 다른 객체가 생성된다.

같은 아이디지만 다른 인스턴스인 것이다.

컬렉션에서 조회한다면? 같은 객체다.

 

 

객체 답게 모델링 할수록 매핑 작업만 늘어난다.

객체를 자바 컬렉션에 저장 하듯이 DB에 저장할 수는 없을까?JPA 기술 등장

 

 

 

 


JPA

Java Persistence API

자바 진영의 ORM 기술 표준

 

ORM

Object Relational Mapping

객체와 관계형데이터베이스 매핑

객체 대로, 관계형 데이터베이스 대로 설계 하고 ORM 프레임워크가 중간에서 매핑해준다.

JPA는 애플리케이션과 JDBC 사이에서 동작한다.

DAO에서 JPA에게 객체를 주면 JPA가 알아서 분석해 SQL을 만들고 JDBC API를 사용해 쿼리를 날려준다.

조회 시에도 id만을 넘겨주면 JPA 가 객체(entity object)를 반환해준다.

 

EJB 엔티티 빈(자바 표준) → 하이버네이트(오픈 소스) → JPA(자바 표준) 으로 발전

JPA는 오픈소스에서 출발한 실용적인 JAVA 표준이다.

  • JPA는 표준 명세(인터페이스의 모음)
  • 구현체로는 거의 하이버네이트를 쓴다.

 

JPA를 왜 사용?

 

- SQL 중심 개발 → 객체 중심 개발 위함

- 생산성

- CRUD시 편리함

- 유지보수

- 필드 변경시 모든 SQL을 수정할 필요가 없다.

- 패러다임 불일치 해결

- 상속 : 알아서 JPA가 조인해 객체 반환

- 연관관계 : 연관관계에 있는 객체를 성능 최적화해 가져옴

- 객체 그래프 탐색 : 객체가 모두 존재해 자유롭게 객체 그래프를 탐색할 수 있음(지연로딩을 통해 모든 객체를 조인해 가져오지는 않는다.)

- 비교하기 문제 : 동일한 트랜젝션에서 조회한 엔티티는 같음을 보장

- 성능

1차 캐시와 동일성 보장 : 같은 트랜잭션 안에서는 같은 엔티티를 반환한다.여러번 조회해도 캐시에서 가져오기 때문에 SQL은 실제 한번만 실행된다.

트랜젝션을 지원하는 쓰기 지연 : 트랜잭션을 커밋할 때까지 INSERT SQL을 모아 한번에 전송한다.

지연로딩 : 객체가 실제 사용될 때 로딩

즉시 로딩 : JOIN으로 한번에 연관된 객체까지 미리 조회

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

 

 

 

 

인프런 자바 ORM 표준 JPA 프로그래밍 - 기본편을 수강하고 정리한 글입니다. 

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