본문 바로가기

WEB/Spring

[JPA] JPA와 JPA의 필요성

💡 JPA(Java Persistence API)

= 자바로 영속 영역을 처리하는 API

  • JPA 상위 개념은 ORM(Object Relational Mapping)이라는 패러다임으로 이어짐
    • → 이는 객체 지향으로 구성한 시스템을 ⇒ 관계형 데이터베이스에 매핑하는 패러다임이다.
  • JPA를 이용하는 개발의 핵심은 객체지향을 통해서 영속 계층을 처리하는 데 있음
    • → JPA를 이용할 때는 테이블과 SQL을 다루는 것이 아니라 ❌ 데이터에 해당하는 객체를 엔티티 객체라는 것으로 다루고 JPA로 이를 데이터베이스와 연동해서 관리한다.

💡 JPA의 필요성

  • 객체와 관계형 데이터베이스의 차이연관관계 - 상속테이블은 외래 키를 사용: JOIN ON M.TEAM_ID = T.TEAM_ID
    • 객체는 Member에서 Team으로는 갈 수 있지만 Team에서 Member로는 참조가 없어서 갈 수가 없다. 테이블은 Member에서 FK로 join해서 Team을 찾을 수 있다. 그리고 반대로도(PK로 FK를) join할 수 있다.
    • RDB만 고려했을 때 설계하면 다음과 같다.
      • 🙈문제점 : 하지만 이렇게 된다면 객체지향스럽지 못하다.
    • public Member{ String id; Long team_id; //team의 외래키 }
    • 그래서 객체 지향적으로 코드를 작성하면 다음과 같다
      • 🙈문제점 : 하지만 이렇게 된다면
        • 저장시 문제점 : DB에 insert할 때 team에서 다시 FK인 team_id를 조회한 후 DB에 넣어주어야 한다. member.getTeam.getId() 로 해서 INSERT INTO 로 데이터에 id 값을 넣는다.
        • 조회 시 문제점 : Member랑 Team을 join 한다.
            1. 데이터를 SQL로 한번에 불러온 다음에
            1. 섞여있는 데이터를 Member와 Team에 대해서 각각 꺼내서 값을 세팅해서 넣은 다음에,
            1. 마지막으로 개발자가 직접 연관관계를 세팅한 후에 반환하면 된다. = 많이 복잡하다...
        🙉그래서 보통 MemberTeam 같은 큰 클래스를 만들어서 거기에 데이터를 일자로 때려 박는다.list.add(member)
      • 그런데 자바 컬렉션에 넣는다고 생각하면 객체 지향적으로 설계한 코드가 매우 좋다. 어차피 컬렉션에 member를 넣을 때, 연관된 team도 참조로 같이 들어가기 때문에.
    • public Member{ String id; Team team; //team의 객체 }
    그런데 자바 컬렉션에 넣는다고 생각하면 객체 지향적으로 설계한 코드가 매우 좋다.
    • 객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다. 참조 등으로 연관된 객체를 자유롭게 가져올 수 있는 것. ↔ 그러나, RDB의 경우 처음 실행하는 SQL에 따라 탐색 범위가 결정되어 버린다.
    • 예시_) Member 객체의 필드로 Team 객체와 Order 객체가 있으며 이때 SQL 문의 Join 문으로 필드의 Team 객체를 함께 가져와서 Member 객체에 넣어줬다고 가정하자.
      • 결과는 Order과는 Join 을 하지 않았기에 getOrder 시 Null이 조회될 것이다.
      • 조회한 엔티티의 필드 범위가 SQL에 의해 결정되기에, Member 필드 안에 Order가 있지만 값을 가져올 수 없다는 것이고 엔티티의 필드값을 신뢰할 수 없게된다.
//==== 객체지향적입장 ====== 
public class Member { private String memberId; private Team team; private Order order; } 

//====RDB 입장==== String sql = "SELECT M.*, T.* FROM MEMBER M JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID" 

Member.getOrder(); //??
    • JPA는 지연로딩이라는 기능이 있어서, member.getTeam이나, member.getOrder 등으로 실제 객체를 조회해서 사용하는 시점에 SQL이 나가서 데이터가 채워진다.
    • 즉, JPA를 사용하면 신뢰할 수 있는 엔티티와 계층이다.
    4) 데이터 식별 방법
    • 같은 식별자여도, DB에서 가져올 때 해당 식별자를 넣어서 new로 생성하다보니 다른 객체로 인식된다.
      • → 하지만 JPA는 동일한 트랜젝션에서 조회한 엔티티는 같음을 보장해준다.
    [Dao에서 Member 객체 받아오기 vs Collection에서 객체 받아오기 차이]
    • Dao에서 Member 객체 받아오기
    • String memebrId=100; Member1 = memberDao.getMember(memberId); Member2 = memberDao.getMember(memberId); // ==== 결과 ====== //Member1 != Member2 memberDAO에서 같은 id로 Member를 조회해온다. member1과 member2는 다르다. 식별자가 똑같아도 SQL 쿼리를 2번 각각 날리고 생성자로 Member를 만들어서 반환하니 달라지는 것이다.
String memebrId=100; 
Member1 = memberDao.getMember(memberId); 
Member2 = memberDao.getMember(memberId); 
// ==== 결과 ======
//Member1 != Member2 memberDAO에서 같은 id로 Member를 조회해온다. member1과 member2는 다르다. 식별자가 똑같아도 SQL 쿼리를 2번 각각 날리고 생성자로 Member를 만들어서 반환하니 달라지는 것이다.
    • Collection에서 객체 받아오기
String memebrId=100; 
Member1 = list.get(memberId);
Member2 = list.get(memberId); 
// ==== 결과 ====== 
//Member1 == Member2 자바 컬렉션에서 조회하는 경우에는 같은 식별자를 넣으면 참조값이 똑같으므로 ==비교로 member1과 member2는 같다고 나온다.
    • String memebrId=100; Member1 = list.get(memberId); Member2 = list.get(memberId); // ==== 결과 ====== //Member1 == Member2 자바 컬렉션에서 조회하는 경우에는 같은 식별자를 넣으면 참조값이 똑같으므로 ==비교로 member1과 member2는 같다고 나온다.
    💡 객체 지향적으로 설계하고, 객체답게 모달링 할수록 매핑 작업만 늘어난다. 그래서 사실상 SQL에 맞춰서 객체를 데이터 전송하는 역할만 하도록 설계하는 경우가 많다.객체를 자바 컬렉션에 저장하듯이 DB에 저장할 수는 없을까?
  • ⇒ JPA - Java Persistence API 등장

 

이 글은 인프런 김영한 강사님의 자바 ORM 표준 JPA 프로그래밍 - 기본편을 참고하여 작성하였습니다.