💡 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 한다.
-
- 데이터를 SQL로 한번에 불러온 다음에
- 섞여있는 데이터를 Member와 Team에 대해서 각각 꺼내서 값을 세팅해서 넣은 다음에,
- 마지막으로 개발자가 직접 연관관계를 세팅한 후에 반환하면 된다. = 많이 복잡하다...
-
- 그런데 자바 컬렉션에 넣는다고 생각하면 객체 지향적으로 설계한 코드가 매우 좋다. 어차피 컬렉션에 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를 사용하면 신뢰할 수 있는 엔티티와 계층이다.
- 같은 식별자여도, DB에서 가져올 때 해당 식별자를 넣어서 new로 생성하다보니 다른 객체로 인식된다.
- → 하지만 JPA는 동일한 트랜젝션에서 조회한 엔티티는 같음을 보장해준다.
- 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는 같다고 나온다.
- ⇒ JPA - Java Persistence API 등장
이 글은 인프런 김영한 강사님의 자바 ORM 표준 JPA 프로그래밍 - 기본편을 참고하여 작성하였습니다.
'WEB > Spring' 카테고리의 다른 글
[JPA] 2장 JPA 시작 (0) | 2023.05.22 |
---|---|
[Spring Security] 스프링 시큐리티란? (0) | 2023.03.08 |
빈 생명주기 콜백 (1) | 2022.09.11 |
같은 타입인 여러 개의 빈들을 조회하고 싶을 때 (1) | 2022.09.10 |
Lombok 라이브러리의 @RequiredArgsConstructor (2) | 2022.09.09 |