Spring/JPA

JPA 소개 #2

묠니르묘묘 2022. 2. 16. 00:24

 

 

🧐 ORM(Object Relational Mapping)이란?

  • 객체와 관계형 데이터베이스를 자동으로 매핑(연결)해주는 것
  • 패러다임의 불일치 문제를 해결 ( JPA소개#1 )
  • 자바 진영에도 여러가지 ORM 프레임워크가 있는데 그 중 하이버네이트 프레임워크가 가장 많이 사용된다.
  • 대중적인 언어에는 대부분 ORM 기술 존재

 

 

🧐 JPA(Java Persistence API)란 무엇인가?

자바 진영의 ORM 기술 표준이다.

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

JPA

위 그림의 동작원리는 다음과 같다.

1. 개발자가 JPA에게 명령한다.

2. JPA가 JDBC API 사용해서 SQL 호출

3. 결과를 받아서 동작

 

 

🧐 객체를 저장하는 JPA 저장 동작원리를 예시로 알아보자

JPA 저장

Member DAO에서 member 객체를 JPA로 넘긴다.

JPA가 member 객체를 분석해서 적절한 SQL을 생성하고 JDBC API를 사용한다.

그렇게 DB에 SQL을 보내서 동작하는 것이다.

앞서 얘기했듯이 여기서도 중요한게 패러다임 불일치 해결이다.

 

 

 

📝 JPA 소개

처음 자바진영에서 EJB가 나왔다가 너무 복잡하고 기술 성숙도가 떨어져서 나온 것이 하이버네이트이다.

그렇게 자바진영에서 하이버네이트를 기반으로 새로운 자바 ORM 기술 표준을 만들었는데 이것이 JPA이다.

JPA를 사용하려면 JPA를 구현한 ORM 프레임워크를 선택해야 한다.

크게 3가지 Hibernate, EclipseLink, DataNucleus가 있는데 Hibernate가 대중적이다.

JPA 구현한 ORM 프레임워크

 

 

🧐 JPA 버전별 특징

JPA 1.0 (JSR 220) 2006년 : 초기 버전, 복합키와 연관관계 기능 부족

JPA 2.0 (JSR 317) 2009년 : 대부분의 ORM 기능 포함, JPA Criteria 추가

JPA 2.1 (JSR 338) 2013년 : 스토어드 프로시저 접근, 컨버터(Converter), 엔티티 그래프 기능 추가

 

 

 

 

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

1. 생산성

JDBC API를 사용하는 반복적인 일을 대신해준다. (CRUD용 SQL)

jpa.persist(member); // 저장
Member member = jpa.find(memberId); // 조회
member.setName("변경할 이름"); // 수정
jpa.remove(member); // 삭제

여기서 특히 수정은 바꾸기만하면 알아서 저장된다.

 

 

2. 유지보수

엔티티에 필드 하나만 추가해도 SQL과 매핑하기 위한 JDBC API 코드를 모두 변경해야 한다.

JPA가 이런 점들을 대신 처리하므로 유지보수 할 코드 수가 줄어든다.

또한 패러다임 불일치 문제를 해결하므로 객체지향 언어가 가진 장점을 활용해 유지보수하기 좋은 도메인 모델 설계가 가능하다.

 

 

3. 패러다임 불일치 해결

JPA 소개#1 에서도 말했지만 상속, 연관관계, 객체 그래프 탐색, 비교하기 같은 패러다임의 불일치 문제를 해결해준다.

 

 

4. 성능

JPA는 애플리케이션과 DB사이에서 동작하므로 다양한 성능 최적화를 시도해볼 수 있는 것들이 많다.

 

1) 1차 캐시와 동일성 보장

  • 같은 트랜잭션 안에서는 같은 엔티티를 반환
  • DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repeatable Read 보장
String memberId = "100";
Member m1 = jpa.find(Member.class, memberId); // SQL로 가져옴
Member m2 = jpa.find(Member.class, memberId); // 캐시에서 바로 가져옴
println(m1 == m2) // true

m2는 캐시에서 가져오므로 SQL을 1번만 실행하게 되는 것이다.

 

 

2) 트랜잭션을 지원하는 쓰기 지연

  • 트랜잭션을 커밋할 때까지 INSERT SQL을 모음
  • JDBC BATCH SQL 기능을 사용해서 한번에 SQL 전송
transaction.begin(); // 트랜잭션 시작
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
// 여기까지 INSERT SQL을 DB에 보내지 않음
// 커밋하는 순간 DB에 INSERT SQL을 모아서 보냄
transaction.commit(); // 트랜잭션 커밋
  • UPDATE, DELETE로 인한 row락 시간 최소화
  • 트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고 바로 커밋
transaction.begin(); // 트랜잭션 시작
changeMember(memberA);
deleteMember(memberB);
비즈니스_로직_수행(); // 비즈니스 로직 수행동안 DB row 락 걸리지 않음
// 커밋하는 순간 DB에 UPDATE, DELETE SQL을 보낸다.
transaction.commit(); // 트랜잭션 커밋

 

 

3) 지연 로딩과 즉시 로딩

  • 지연 로딩 : 객체가 실제 사용될 때 로딩
  • 즉시 로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회

예를 들면 member를 조회한다?

지연 로딩이면 MEMBER 조회만 하고, team의 정보를 조회하려 할 때 TEAM에 대한 조회 SQL이 보내지게 된다.

즉시 로딩은 member만 조회하더라도 연관된 TEAM까지 전부 조회해버린다.

 

 

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

데이터베이스마다 데이터타입, 페이징 처리 등 사용법이 다르다.

JPA는 애플리케이션과 데이터베이스 사이에 추상화된 데이터 접근 계층을 제공해서 DB에 종속되지 않도록 한다.

그래서 DB의 종류를 바꾸기 매우 쉽다.

벤더 독립성

 

 

 

📝 정리

Q. 통계 쿼리처럼 매우 복잡한 SQL은 어떻게 하나요?

A. JPA는 통계 쿼리보다는 실시간 처리용 쿼리에 최적화되어 있다.

     따라서 네이티브 SQL, 마이바티스, JdbcTemplate 같은 SQL 매퍼 형태의 프레임워크를 혼용하는 것도 좋은 방법이다.

 

Q. 마이바티스와 어떤 차이가 있나요?

A. 마이바티스나 스프링 JdbcTemplate을 SQL 매퍼라고 한다. 이름 그대로 객체와 SQL을 매핑한다.

    결국 개발자가 SQL을 직접 작성해야 하므로 SQL 의존적을 피할 수 없다.

    반면 ORM은 객체와 테이블을 매핑만하면 알아서 SQL을 만들어서 DB 관련 처리를 하므로 SQL 의존적을 벗어날 수 있다.

 

Q. 하이버네이트 프레임워크를 신뢰할 수 있나요?

A. 2001년 공개 후 지금도 발전하는 성숙한 ORM 프레임워크이다.

    전 세계적으로 많이 쓰이며 Atlassian, AT&T, Cisco 같은 업체들도 사용한다.

 

Q. 국내에서 마이바티스를 많이 사용하는데요?

A. 국내에서 마이바티스를 많이 사용하지만, 전 세계적으로 조사하면 하이버네이트 ORM 프레임워크 비중이 절대적으로 많다.

 

 


자바 ORM 표준 JPA 프로그래밍 / 김영한 지음 / 에이콘출판주식회사 출판

자바 ORM 표준 JPA 프로그래밍 - 기본편 / 김영한 / 인프런 강의