dev-miri
[JPA] JPA와 모던 자바 데이터 저장 기술 본문
데이터베이스 접근 방식으로 jdbc를 사용하다가, 요새 실무에서 jpa를 많이 사용한다고 하기도 하고,
이번에 시작하게 된 프로젝트에서 jpa를 사용하기로 해서 JPA 공부를 시작하였다.
실전으로 돌입해서 공부하는 방식보다는, 개념을 천천히 짚어가며 차근차근 공부하는 방식을 좋아해서 실습부터 먼저 들어가기 보다, JPA가 무엇인지 먼저 공부해보기로 했다.
많은 추천을 받은 김영한 강사님의 JPA 로드맵 중 첫번째 강의인 자바 ORM 표준 JPA 프로그램 강의를 수강하기로 했다.
https://www.inflearn.com/roadmaps/149
김영한의 스프링 부트와 JPA 실무 완전 정복 로드맵 - 인프런 | 로드맵
[사진][사진] 현역 개발 팀장이 전해주는진짜 실무 노하우. 실무에서 스프링 부트와 JPA를 재대로 알고 사용하는 것은 매우 중요합니다. 조 단위의 거래 금액을 처리하는 주문, 결제, 정산 같은 핵
www.inflearn.com
현재 개발의 문제점은?
애플리케이션은 객체 지향 언어를 사용한다. 예시로는 Java가 있다.
데이터베이스는 관계형 DB를 사용한다. Oracle 혹은 MYSQL ....
지금 시대는 객체를 관계형 DB에 관리를 한다. 그러다보면...SQL 지옥에 빠지게 된다...
spring boot로 간단한 쇼핑몰 제작 프로젝트를 제작한 적이 있는데, 정말 간단한 쿼리문이어도 계속 오타나 잘못된 부분이 생겨서 계속 수정과정을 거쳐야 했다.
또, 기획에서 작은 변동 사항이 생겨면 수많은 코드에서 쿼리문 수정 과정을 거쳐야 한다.(수정하는게 두려워진다...)
즉, SQL 의존적인 개발을 하게 되고, 제한된 시간에 개발을 해내야 하는 개발자로서, 다른 부분에 신경쓸 시간이 줄어들게 되는 것이다.
이러한 문제는 객체와 관계형 데이터베이스의 패러다임의 불일치에서 발생한다 .
객체와 관계형 데이터베이스의 차이점은 4가지가 있다.
1. 상속 : 객체는 상속 관계가 있지만, 관계형 DB에는 상속 관계가 없다.
2. 연관관계 : 객체는 참조를 사용하지만, 테이블은 외래 키를 사용한다.
3. 데이터 타입
4. 데이터 식별 방법 : 자바 컬렉션에 멤버를 저장하고 불러오는 것과 sql을 통해 불러오는 것은 결과 값이 다르다
String memberId = "100";
Member member1 = memberDAO.getMember(memberId);
Member member2 = memberDAO.getMember(memberId);
member1 == member2; //다르다
//자바 컬렉션에서 조회
String memberId = "100";
Member member1 = list.get(memberId);
Member member2 = list.get(memberId);
member1 == member2; //같다
차이점들이 문제를 야기한다면, 객체를 자바 컬렉션에 저장 하듯이 DB에 저장할 수 없을까? 라는 질문에 다다르게 된다
이 방법이 바로 JPA이다.
JPA란 Java Persistence API의 약자로, 자바 진영의 ORM 기술 표준이다.
ORM이란 Object-relational mapping(객체관계매핑)으로, 객체는 객체대로 설계하고, 관계형 데이터베이스는 관계형 데이터베이스대로 설계한 후 ORM 프레임워크가 중간에서 매핑하는 기술이다. 대중적인 언어에는 대부분 ORM 기술이 존재한다.
JPA의 동작 원리는 다음 그림과 같다.

JPA는 독립적인 개체가 아니라, JPA가 JDBC API를 호출하고, JDBC가 SQL로 DB에 접근하는 방식이다.



책 내부에 이런 그림이 있었는데, 강의에서 설명을 들었겠지만 글을 쓰는 지금은 기억이 나지 않아서 검색을 해서 찾아보았다.
아래는 자세하게 정리한 글이다.
https://devmiri.tistory.com/27
간단하게 정리하면, JPA는 인터페이스의 모음이다(=기술명세). 특정 기능을 하는 라이브러리가 아니라, 자바 어플리케이션에서 관계형 데이터베이스를 어떻게 사용해야 하는지를 정의하는 한 방법일 뿐이다.
hibernate는 JPA의 구현체이다. entityManger와 같은 인터페이스를 직접 구현한 라이브러리이다. JPA와 Hibernate는 마치 자바의 interface와 해당 interface를 구현한 class와 같은 관계이다.

https://suhwan.dev/2019/02/24/jpa-vs-hibernate-vs-spring-data-jpa/
JPA, Hibernate, 그리고 Spring Data JPA의 차이점
개요 Spring 프레임워크는 어플리케이션을 개발할 때 필요한 수많은 강력하고 편리한 기능을 제공해준다. 하지만 많은 기술이 존재하는 만큼 Spring 프레임워크를 처음 사용하는 사람이 Spring 프레
suhwan.dev
JPA를 왜 사용해야 하는가?
-SQL 중심적인 개발에서 객체 중심으로 개발
-생산성
-유지보수
-패러다임의 불일치 해결
-성능
-데이터 접근 추상화와 벤더 독립성
-표준
생산성에 대해 알아보자 : JPA와 CRUD
-CRUD란 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서 일컫는 말이다. 사용자 인터페이스가 갖추어야 할 기능(정보의 참조/검색/갱신)을 가리키는 용어로서도 사용된다.
-저장 : jpa.persist(memver)
-조회 : Member member = jpa.find(memberId)
-수정 : member.setName("변경할 이름")
-삭제 : jpa.remove(member)
유지보수 : 기존에는 필드 변경 시 모든 SQL을 수정해주었어야 한다. 하지만 JPA를 사용하면, 필드만 추가해주면 되고, SQL은 JPA가 처리하게 된다.
JPA는 패러다임의 불일치를 해결해줘서, CRUD만 해주면 나머지 SQL은 JPA가 처리해준다.
JPA와 상속 관계를 자세히 알아보자.

위와 같은 관계가 있다고 하자.
기존 JPA를 사용하지 않을 때에는, Album을 저장하려고 하면
1. 객체 분해
2. INSERT INTO ITEM
3. INSERT INTO ALBUM
과정을 거쳐야 했다.
Album을 조회하고자 할 때에는
1. 각각의 테이블에 따른 조인 SQL 작성
2. 각각의 객체 생성
3. 상상만 해도 복잡...
4. 따라서 DB에 저장할 객체에는 상속 관계를 사용하지 않는다.
JPA를 사용할 때, Album을 저장하고자 하면
jpa.persist(album);
코드 한 줄만 써주면 SQL 과정을 JPA가 처리해준다.
Album을 조회하고자 할 때는
Album album = jpa.find(Album.class, albumId);
코드를 서주면 나머지 과정은 JPA가 처리해준다.
연관관계를 저장할 때, 객체 그래프를 탐색할 때에도 JPA를 사용하지 않을 때에 비해 아주 간단하게 해결할 수 있다.(뒤에서 더 상세하게 설명)
String memberId = "100";
Member member1 = list.get(memberId);
Member member2 = list.get(memberId);
member1 == member2; //같다
동일한 트랜잭션에서 조회한 엔티티는 같음을 보장한다. 이는 자바의 컬렉션에 저장했을 때와 같아 패러다임의 불일치를 해결해준다.
JPA의 성능 최적화 기능은 다음과 같다
1. 1차 캐시와 동일성(identity) 보장
2. 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)
3. 지연 로딩(lazy Loading)
1차 캐시와 동일성 보장
1. 같은 트랜잭션 안에서는 같은 엔티티를 반환한다 - 약간의 조회 성능을 향상 해준다
2. DB Isolation Level이 Read Commit이어도 애플리케이션에서 Reatable Read 보장해준다. (아직 무슨소리인지 모르겠다)
String memberId = "100";
Member member1 = list.get(memberId); //SQL
Member member2 = list.get(memberId); //캐시
pringln(member1 == member2); //true
첫번째 멤버를 불러올 대는 sql을, 두 번째는 캐시를 사용해서 sql을 한 번만 불러오게 되므로 성능을 향상시킬 수 있다.
트랜잭션을 지원하는 쓰기 지연 - INSERT
1. 트랜잭션을 커밋할 때까지 INSERT SQL을 모은다
2. JDBC BATCH SQL 기능을 사용해서 한번에 SQL을 전송한다.
transaction.begin(); //[트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 모아서 보낸다.
transaction.commit(); //[트랜잭션] 커밋
트랜잭션을 지원하는 쓰기 지연 - UPDATE
1. UPDATE, DELETE로 인한 로우(ROW)락 시간 최소화
2. 트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고, 바로 커밋
transaction.begin(); //[트랜잭션] 시작
changeMember(memberA);
deleteMemver(memberB);
비즈니스 로직 수행(); //비즈니스 로직 수행 동안 DB 로우 락이 걸리지 않는다
//커밋하는 순간 데이터베이스에 UPDATE, DELETE SQL을 보낸다.
transaction.commit(); //[트랜잭션] 커밋
지연 로딩과 즉시 로딩
-지연 로딩 : 객체가 실제 사용될 때 로딩
-즉시 로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회

즉, ORM은 객체와 RDB 두 기둥위에 있는 기술이다.
라는 말로 마무리할 수 있을 것 같다.
다음 글부터는 JPA 실습 과정을 정리해 볼 것이다.
'JPA' 카테고리의 다른 글
| [JPA] Hello JPA - 애플리케이션 개발 (0) | 2022.08.04 |
|---|---|
| [JPA] 인터페이스, api, 라이브러리, 프레임워크 개념 정리/hibernate와 jpa (0) | 2022.08.04 |
| JPA 프로젝트 생성하기(maven 설치/intellij maven 연동, jdk 버전 변경) (0) | 2022.07.13 |