어플리케이션 개발은 보통 객체 지향 언어
데이터 베이스에서는 주로 관계형 DB에 데이터 보관 및 관리
-> 객체를 관계형 DB에 관리해야 하는 시대
-> SQL에 의존적인 개발을 피하기는 어렵다.
객체 vs 관계형 DB
객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공
객체(object)는 RDB, NoSQL, File 등 다양하게 저장 가능
현실적인 대안은 관계형 DB (주로 NoSQL은 보조적인 수단으로 사용)
객체->SQL 변환->RDB에 SQL로 전달
SQL Mapper의 역할을 개발자가 함
객체의 상속 관계를 RDB에서는 표현하지 못함.-> 데이터를 부모/자식으로 분리하여 사용 시에는 table을 join하여 사용.
--> case마다 join 쿼리를 모두 작성해야 함
->복잡해짐-> DB에 저장할 객체에는 상속관계를 쓰지X
자바 컬렉션에 저장하면? add, get 코드 한 줄로 해결
--> 객체이기 때문에 가능한 것
객체는 참조를 사용 ex.member.getTeam()
테이블은 FK를 사용 ex. join on m.team_id=t.team_id
테이블에 맞춘 관계 저장
-> 객체다운 모델링이 아닐 수 있음.(참조가 아니기 때문)
객체는 참조로 연관관계를 갖는다.
-> DB에 insert 까다로움
->연관관계를 포함한 객체가 존재.
list.add(member);
Membet member=list.get(memberId);
Team team=member.getTeam();
객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다.
처음 실행하는 SQL에 따라 탐색 범위가 결정됨.
SELECT M.,T.
FROM MEMEBER M
JOIN TEAM T ON M.TEAM_ID=T.TEAM_ID
member.getTeam(); //OK
member.getOrder(); //null. 처음에 조회가 안되었기 때문.
--> 엔터티 신뢰 문제 발생(객체를 믿고 쓸 수 없게 됨.)
모든 객체를 미리 로딩할 수는 없다.
방법1>한번에 데이터를 모두 join시켜야 하기 때문에 성능 면에서도 좋지 않음.
방법2>case별로 조회 메소드를 생성해야 함.
----> 객체답게 모델링할 수록 mapping 작업이 늘어난다.
ORM
객체와 RDB를 Mapping해주는 기술.
-Object-relational mapping(객체 관계 매핑)
-객체는 객체대로 설계 / RDB는 RDB대로 설계
-ORM 프레임워크가 중간에서 매핑
-대중적인 언어에는 대부분 ORM 기술이 존재
멤버 엔터티를 저장해 줘 라고 jpa에 던지면, 분석해서 insert 쿼리까지 만들어주고, 패러다임의 불일치까지 해결해 줌.
select 쿼리 생성, jdbc api 사용, 결과 오브젝트를 반환,패러다임 불일치 해결
JPA는 interface의 모음이다.
-Hibernate, EclipseLink,etc
JPA를 사용해야 하는 이유
- SQL 중심적인 개발에서 객체 중심으로 개발
- 생신성
- 유지보수
- 패러다임의 불일치 해결
- 성능
- 데이터 접근 추상화와 벤더 독립성
- 표준
저장: jpa.persist(member)
조회: Member member=jpa.find(memberId)
수정: member.serName("변경할 이름")
삭제: jpa.remove(member)
-기존: 필드 변경 시 모든 SQL 수정
-JPA: 필드만 추가하면 됨. SQL은 JPA가 처리하기 떄문
상속, 조회, 연관관계/객체 그래프 탐색 모두 해결
엔터티, 계층 신뢰O (객체 그래프 탐색이 자유로움)
비교하기-JPA는 동일한 트랜잭션에서 조회한 엔티티는 같음을 보장한다.
1차 캐시와 동일성(identity) 보장
1) 같은 트랜잭션 안에서는 같은 엔터티 반환->약간의 조회 성능 향상
2) DB Isolation Lever이 Read Commit이어도 애플리케이션에서 Repeatable Read 보장
트랜잭션을 지원하는 쓰기 지연(transacional write-behind) -insert
1) 트랜잭션을 커밋할 때까지 insert sql을 모아둠.
2) JDBX BATCH SQL 기능을 사용해서 한번에 SQL 전송
transaction.begin(); //트랜잭션 시작
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
//아직 insert문 DB에 보내지 않음.
transaction.commit();
//트랜잭션 commit-> DB에 insert SQL을 모아 보냄.
//---> 네트워크 통신 비용이 줄어든다.