그동안 단순 CRUD만 쓸줄 알뿐 정확한 JPA , JPA과 어떤 동작으로 수행하는지 모르고 사용하였다. 그리고 그동안 너무 효율성이 안좋게 쓴 느낌이 없잖아 있어 이참에 JPA 를 확실히 잡고 가기 위해 해당 책을 읽게 되었다.
처음으로는 SQL을 직접 다룰때 발생하는 문제점에 대해서 다룬다
무순 문제점이 있을까
public class Main{
private String memberId;
private String name;
}
다음 같이 회원 객체가 있을때 이를 CRUD 시킬 생각이다
public class MemberDAO{
public Member find(String memberId){}
}
// sql쿼리 작성
SELECT MEMBER_ID,NAME FROM MEMBER M WHERE MEMBER_ID = ?
// sql jdbc 사용하여 실행
ResultSet rs = stmt.executeQury(sql);
//조회결과를 Member에 매핑
String memberld = rs.getString("MEMBER_ID”》;
String name = rs.getString("NAME”);
Member member = new Member();
member.setMemberld(memberld);
member.setName(name);
이처럼 조회 쿼리가 완성 되었다
이제 등록 쿼리를 줄 차례이다
//회원 등록 sql 쿼리 작성
String sql = "INSERT INTO MEMBER(MEMBER_ID, NAME) VALUES(?,?)";
//회원 객체 값 꺼내 등록 sql 작성
pstmt.setstring(1, member.getMemberld());
pstmt.setstring(2Z member.getName());
//실행
pstmt.executeUpdate(sql);
수정과 삭제도 이와 비슷하게 JDBC API를 사용하는 일을 반복적으로 수행한다
만약 컬랙션이였다면
list.add(member);
다음과 같이 저장 하면 된다 (필드를 일일이 조회하고 일일이 저장 쿼리를 안만들어도 됨)
하지만 데이터 베이스는 객체 구조와 다른 데이터 중심 구조 이므로 객체를 직접 저장 조회 가 불가능 하다
따라서 중간에 sql과 jdbc api를 사용하여 변환 작업을 직접 해주어야한다
여기서 발생 문제는 앞서 본
"" 반복 반복 반복 ""
또한 앞서 본 코드는 SQL 에 너무 의존적이다
만약 앞서 본 코드에서 회원에 다른 필드도 추가 하고 싶다면
그럼 우리는 등록 쿼리, 업데이트 쿼리, 조회 쿼리 등등 연관된 SQL 쿼리들은 모두 변경해줘야 한다
애플리케이션에서 SQL을 직접 다룰때 문제점을 요약하면
그럼 JPA는 이와 같은 문제를 어떻게 해결 할까
JPA를 사용하면 객체를 데이터베이스에 저장하고 관리 할 때 개발자가 직접 SQL을 작성하는 것이 아닌 JPA 제공 API를 사용하면 됨 그럼 JPA가 적절한 SQL을 생성하여 데이터 베이스 전달
객체는 상속이라는 기능을 가지고 있지만 테이블은 상속이라는 기능이 없다
그나마 데이터 베이스 모델링에서 이야기하는 슈퍼타입 서브 타입 관계를 사용하면 유사항 형태로 설계 할 수 있지만 쿼리가 복잡하다
abstract class Item{
Long id;
String name;
int price;
}
lass Album extends Item {
String artist;
}
class Movie extends Item {
String director;
String actor;
}
class Book extends Item{
String author;
String isbn;
}
// ALBUM 객체 저장시
NSERT INTO ITEM ...
INSERT INTO ALBUM ...
// MOVIE객체 저장시
INSERT INTO ITEM ...
INSERT INTO MOVIE ...
DBC API를 사용해서 이 코드를 완성하려면 부모 객체에서 부모 데이터만 꺼내
서 ITEM용 INSERT SQL을 작성하고 자식 객체에서 자식 데이터만 꺼내서 ALBUM
용 INSERT SQL을 작성 해야 하는데, 작성 해야 할 코드량이 만만치 않다
이는 곳 패러다임 불일치를 해결하려고 소모하는 비용 ..
JPA에서는 상속과 관련된 패러다임 불일치 문제를 개발자 대신 해결해준다
// 다음 같이 JPA 사용하여 저장시
jpa.persist(album);
// JPA에서 다음과 같이 SQL 생성
INSERT INTO ITEM ...
INSERT INTO ALBUM ...
// 객체
class Member {
Team team; // 참조
Team getTeam() {
return team;
}
}
class Team {
}
// RDB
class Member {
String id; //MEMBER_ID 컬럼 사용
Long teamld; //TEAM_ID FK 컬럼 사용
String username; / /USERNAME 컬럼 사용
}
class Team {
Long id; //TEAM_ID PK 사용
String name; //NAME 컬럼 사용
}
객체에서 조회할대 참조를 사용해서 연관된 객체를 찾는것
객체
마음껏 그래프를 탐색할 수 있어야함 그러나 처음 실행하는 SQL에 따라 탐색할 수 있는 객체 그래프 범위가 정해져 그외 객체 그래프는 데이터 없으므로 탐색 불가
SELECT M.*, T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
member.getOrder(》; //null > 다음과 같이 탐색 불가
class MemberService {
public void process() {
Member member = memberDAO.find (memberId);
member.getTeam(); //member->team 객체 그래프 탐색이 가능한가?
member.getOrder().getDelivery(); //???
}
}
이는 엔티티가 sql 에 논리적 종속 되어 있어 문제
memberDAO. getMember (); //Member만 조회
Team 조회
meinberDAO.getMenmberWithOrderWithDeliveryO "/Member와 Order외- Delivery 조회
다음과 같이 여러 메소드를 상황에 따라 만들어 사용해야함
JPA는 객체 그래프를 마음껏 탐색 가능하다
JPA는 연관된 객체를 사용하는 시점에서 적절한 SQL을 실행한다 따라 실 객체를 사용하는 시점까지 데이터베이스 조회를 미룬다 해서 지연로딩이라 한다
JPA 지연로딩을 투명하게 처리한다
지연 로딩 예시
//처음조회 시점에 SELECT MEMBER SQL
Member member = jpa .find (Member. class, memberld);
Order order = member.getOrder();
order. getOrderDate (); "Order를 사용하는 시점에 SELECT ORDER SQL
Member 를 사용할때 마다 Order를 함께 사용하면 이렇게 한 테이블씩 조회 하는 것보다 Member를 조회하는 시점에 sql 조인을 사용해 Member 와 Order를 함께 조회하는 것이 효과적
JPA는 이런 지연로딩을 설정을 통해 간단하게 정의할 수 있다.
class MemberDAO {
public Member getMember(String memberld) {
String sql = "SELECT * FROM MEMBER WHERE MEMBER_ID = ?";
//JDBC API, SQL 실행
return new Member();
}
}
String memberld = "100”;
Member member1 = memberDAO.getMember(memberld);
Member member2 = memberDAO.getMember(memberld);
member1 == member2; //다르다
DAO 를 다음과 같이 정의 하면 같은 ID 로 조회를 했어도 new를 통해 새로운 각 인스턴스가 생겨 == false 가 나온다
이러한 패러다임 불일치 문제를 해결하기 위해 데이터베이스 같은 로우를 조회 할때 같은 인스턴스 반환하도록 구현하는 것은 쉽지 않다
JPA 비교
String memberId = "100";
Member member1 = jpa.find (Member.class, memberld);
Member member2 = jpa. find (Member. class z memberld);
member1 == member2; //같다.
JPA는 같은 트랜잭션일 때 같은 객체가 조회된다는 것이 보장한다
JPA는 객체 모델과 관계형 데이터 베이스 모델의 지향하는 서로 다른 패러다임 문제를 해결해주고 유지하게 도와준다
ORM: 객체와 관계형 데이터베이스 매핑
ORM 프래임 워크가 객체와 테이블을 매핑해 패러다임 불일치 문제를 개발자 대신 해결
객체를 자바 컬렉션에 저장하듯이 ORM 프레임 워크 저장 -> ORM 프레임 워크 적절한 INSERT SQL 생성 -> 데이터베이스 객체 저장
다양한 패러다임 불일치 문제 해결
JPA 는 어플리케이션과 JDBC 사이에서 동작

