반응형

개요

 

인프런 강의를 참고 하여 JPA에 대해 알아보았습니다.

 


ORM이 뭘까...?

 

- Object-relational mapping(객체 관계 매핑)

- 객체는 객체대로 설계

- 관계형 데이터베이스는 관계형 데이터베이스대로 설계

- ORM 프레임워크가 중간에서 매핑

- 대중적인 언어에는 대부분 ORM 기술이 존재

 


JPA란?

- Java Persistence API 

- 자바 진영의 ORM 기술 표준입니다.

- 인터페이스의 모음입니다. 즉, 실제로 동작하는 것이 아닙니다.

- JPA 인터페이스를 구현한 대표적인 오픈소스가 Hibernate라고 할 수 있는데, 실제로 우리나라에서는 mybatis를 많이 사용하지만, 세계적으로는 이 Hibernate가 많이 사용되는 모습을 볼 수 있습니다.

 

 


JPA동작 

 

JPA는 애플레케이션과 JDBC 사이에서 동작합니다.

 

개발자가 JPA를 사용하면, JPA 내부에서 JDBC, API를 사용하여 SQL을 호출하여 DB와 통신합니다.

즉, 개발자가 직접 JDBC,API 와 SQL을 쓰는 것이 아닙니다.

 


JPA 동작 - (저장)

 

MemberDAO에서 객체를 저장하고 싶을 때, 개발자는 JPA에 Member 객체를 넘깁니다.

그렇게 되었을 때.... JPA는 3가지의 동작과정을 수행합니다.

 

1. Member 엔티티를 분석합니다.

2. INSERT SQL문을 생성합니다.

3. JDBC API를 사용하여 SQL을 실행시켜 DB에 적용합니다.

 


JAP 동작 - (조회)

 

 

Member 객체를 조회하고 싶을 때, 개발자는 member의 pk 값을 JPA에 넘깁니다.

그렇게 되었을 때... JPA는 4가지의 동작과정을 수행합니다.

 

1. 엔티티의 매핑 정보를 바탕으로 적절한 SELECT SQL을 생성합니다.

2. JDBC API를 사용하여 SQL을 실행시켜 DB에 적용합니다.

3. DB로부터 결과를 받아옵니다.

4. 결과(ResultSet)를 객체에 모두 매핑합니다.

 

 

여기서 가장 중요하다고 할 수있는 특징이 나타나는데...

쿼리를 JPA가 만들어 주기 때문에 Object와 RDB간의 패러다임 불일치를 해결할 수 있습니다.  

 

여기서 패러다임 불일치란?

데이터베이스는 데이터 중심으로 구조화되었습니다. 즉 객체의 상속, 다형성 같은 개념이 없는데, 그렇다보니 객체와 데이터베이스가 지향하는 점이 다릅니다. 이것을 객체와 데이터베이스의 패러다임 불일치라고 합니다.

 


JPA를 왜 사용하는가?

 

1. 생산성

  • 저장 : jpa.persist(member)
  • 조회 : Student studnet = jpa.find(memberId)
  • 수정 : stduent.setName("변경할 이름")
  • 삭제 : jpa.remove(member)

CRUD가 간단하게 가능합니다. 특히 수정이 굉장히 간단하게 해결이 됩니다.

 

2. 유지보수

  • 기존 : 필드 변경 시 모든 SQL을 수정해야 한다.
  • JPA : 필드만 추가하면 된다. SQL은 JPA가 처리하기 때문에 직접 수정 할 필요가 없다.

 

3. Object와 RDB 간의 패러다임 불일치 해결

 


JPA와 상속

 

 

저장

  • 개발자가 할일
jpa.persist(album);
  • 나머진 JPA가 처리
INSERT INTO ITEM ..

INSERT INTO ALBUM ...

 

조회

  • 개발자가 할일
Album album = jpa.find(Album.class, albumId);
  • 나머진 JPA가 처리
SELECT I.*, A.* 
FROM ITEM I 
JOIN ALBUM A ON I.ITEM_ID = A.ITEM_ID

 


JPA와 연관관계

 

  • 객체의 참조로 연관관계 저장 가능
member.setTeam(team);
jpa.persist(member);

 

JPA와 객체 그래프 탐색

  • 신뢰할 수 있는 엔티티, 계층
class MemberService { 
      ...
      public void process() { 
          /* 직접 구현한 DAO에서 객체를 가져온 경우 */
          Member member1 = memberDAO.find(memberId); 
          member1.getTeam(); // 엔티티를 신뢰할 수 없음 
          member1.getOrder().getDelivery(); 
          /* JPA를 통해서 객체를 가져온 경우 */
          Member member2 = jpa.find(Member.class, memberId); 
          member2.getTeam(); // 자유로운 객체 그래프 탐색
          member2.getOrder().getDelivery(); 
      } 
}
  • 내가 아닌 다른 개발자가 직접 구현한 DAO에서 가져오는 경우
    • DAO에서 직접 어떤 쿼리를 날렸는지 확인하지 않는 이상, 그래프 형태의 관련된 객체들을 모두 잘 가져왔는지 알 수가 없다.
  • JPA를 통해서 가져오는 경우
    • 객체 그래프를 완전히 자유롭게 탐색할 수 있게 된다.
    • 지연 로딩 전략(Lazy Lodaing) 사용
      • 관련된 객체를 사용하는 그 시점에 SELECT sql을 날려서 객체를 가져오는 전략

 

JPA와 비교

  • 동일한 트랜잭션에서 조회한 엔티티는 같음을 보장한다.
String memberId = "100"; 
Member member1 = jpa.find(Member.class, memberId); // DB에서 가져옴 
Member member2 = jpa.find(Member.class, memberId); // 1차 캐시에서 가져옴
member1 == member2; //같다.

 


4. JPA의 성능 최적화 기능

 

  • 중간 계층이 있는 경우 아래의 방법으로 성능을 개선할 수 있는 기능이 존재한다.
    • 모아서 쓰는 버퍼링 기능
    • 읽을 때 쓰는 캐싱 기능
  • JPA도 JDBC API와 DB 사이에 존재하기 때문에 위의 두 기능이 존재한다.

 

1차 캐시와 동일성(identity) 보장 - 캐싱 기능

  • 같은 트랜잭션 안에서는 같은 엔티티를 반환 - 약간의 조회 성능 향상 
String memberId = "100"; 
Member m1 = jpa.find(Member.class, memberId); // SQL 
Member m2 = jpa.find(Member.class, memberId); // 캐시 (SQL 1번만 실행, m1을 가져옴)
println(m1 == m2) // true

 

  • 결과적으로, SQL을 한 번만 실행한다.
  • DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repeatable Read보장

 

트랜잭션을 지원하는 쓰기 지연(transaction write-behind) - 버퍼링 기능

  • INSERT
  • /** 1. 트랜잭션을 커밋할 때까지 INSERT SQL을 모음 */
    transaction.begin();  // [트랜잭션] 시작
    em.persist(memberA); 
    em.persist(memberB); 
    em.persist(memberC); 
    // -- 여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
    // 커밋하는 순간 데이터베이스에 INSERT SQL을 모아서 보낸다. --
    /** 2. JDBC BATCH SQL 기능을 사용해서 한번에 SQL 전송 */
    transaction.commit(); // [트랜잭션] 커밋
  • 트랜잭션을 Commit 할 때까지 INSERT SQL을 메모리에 쌓는다.
    • 이렇게 하지 않으면 DB에 INSERT 쿼리를 날리기 위한 네트워크를 3번 타게 된다.
  • JDBC Batch SQL 기능을 사용해서 한번에 SQL을 전송한다.
    • JDBC Batch를 사용하면 코드가 굉장히 지저분해진다.
    • 지연 로딩 전략(Lazy Lodaing) 옵션을 사용한다.

 

  • UPDATE
  • /** 1. UPDATE, DELETE로 인한 로우(ROW)락 시간 최소화 */
    transaction.begin();  // [트랜잭션] 시작
    changeMember(memberA);  
    deleteMember(memberB);  
    비즈니스_로직_수행();     // 비즈니스 로직 수행 동안 DB 로우 락이 걸리지 않는다.    
    // 커밋하는 순간 데이터베이스에 UPDATE, DELETE SQL을 보낸다.
    /** 2. 트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고, 바로 커밋 */
    transaction.commit(); // [트랜잭션] 커밋
  • UPDATE, DELETE로 인한 로우(ROW)락 시간 최소화
  • 트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고, 바로 커밋

 

 

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


 

반응형

+ Recent posts