현재 대부분 현대적인 애플리케이션은 객체 지향 언어를 사용한다.
또한 데이터를 저장하기 위해서는 관계형 DB를 사용한다.
결론적으로 지금 시대는 객체를 관계형 DB에 관리한다.
문제점이 있다.
애플리케이션은 객체지향적으로 설계하는데 DB는 SQL만 알아듣기 때문에 SQL을 계속 작성해서 날려줘야 한다. 이러면 바로 SQL 중심적인 개발을 하게 된다.
예를 들어서, 기획자가 회원을 설계해달라 하였다.
우리는 회원 테이블 만들고, 회원 객체 만들고, 쿼리를 작성할것이다.
그렇게 다 만들었는데 갑자기 연락처 컬럼을 추가해달라고 한다면?
객체, 테이블, 쿼리를 전부 수정해야하는 번거로움이 생긴다.
결국, 관계형 DB를 사용하는 이 상황에서는 SQL에 의존적인 개발을 피하기 어렵다.
SQL 작성문제를 넘어서서 패러다임의 불일치라는 문제가 있다.
객체가 먼저있고, 객체를 저장할 저장소를 고른다고 생각해보자.

현실적으로 관계형 DB를 대체할만한건 없다.
현실적인 대안은 관계형 데이터베이스

객체를 RDB에 저장하기 위해서는 SQL로 바꿔야한다. 결국 SQL을 짜야하는데 그것을 다 개발자들이 한다는 것이다.
개발자 = SQL 매퍼

객체의 상속관계를 관계형 DB에 넣는것은 매우 힘들다.
슈퍼타입, 서브타입에 저장한다해도, 조회할때 쉽지 않다.
Album 조회
1. 각각의 테이블에 따른 조인 SQL 작성...
2. 각각의 객체 생성...
3. 상상만해도 복잡
4. 더 이상의 설명은 생략...
5. 그래서 DB에 저장할 객체에는 상속관계 안쓴다
만약 객체를 자바 컬렉션에 저장하고 조회한다면?
list.add(album);
Album album = list.get(albumId);
//부모 타입으로 조회 후 다형성 활용
Item item = list.get(albumId);
단순하게 가능해진다.

객체는 참조로 연관된 객체를 찾아갈 수 있다.
그런데 테이블은 외래키 사용함. MEMBER에서 TEAM 가고싶다면, MEMBER에 있는 TEAM_ID(FK)와 TEAM의 PK를 JOIN하면 된다.
그런데 객체는 Member에서 Team으로는 갈 수 있지만, 역으로 Team에서 Member로는 가지 못한다. (반대방향으로 참조가 없기 때문)
하지만 테이블의 경우 PK와 FK로 JOIN하는 것이기 때문에 양방향으로 가능하다.
객체를 테이블에 맞추어 모델링
따라서 보통 객체를 테이블에 맞추어 모델링을 한다.
class Member {
String id; //MEMBER_ID 컬럼 사용
Long teamId; //TEAM_ID FK 컬럼 사용
String username; //USERNAME 컬럼 사용
}
class Team {
Long id; //TEAM_ID PK 사용
String name; //Name 컬럼 사용
}
테이블에 맞춘 객체 저장
class Member {
String id; //MEMBER_ID 컬럼 사용
Long teamId; //TEAM_ID FK 컬럼 사용
String username; //USERNAME 컬럼 사용
}
INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES ...
객체지향스러운 설계가 아니다.
객체다운 모델링
class Member {
String id; //MEMBER_ID 컬럼 사용
Team team; // "참조로 연관관계를 맺는다!!!!"
String username;//USERNAME 컬럼 사용
Team getTeam() {
return team;
}
}
class Team {
Long id; //TEAM_ID PK 사용
String name; //NAME 컬럼 사용
}
객체 모델링 저장
class Member {
String id; //MEMBER_ID 컬럼 사용
Team team; // "참조로 연관관계를 맺는다!!!!"
String username;//USERNAME 컬럼 사용
Team getTeam() {
return team;
}
}
** member.getTeam().getId(); **
INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES...
테이블에 필드 매핑해서 넣어야하는데, 객체 모델링에는 외래키 값을 나타내는 필드가 없거 Team 객체에대한 참조만 존재함.
Team에 대한 참조를 타고가서 Id를 가져와서 FK로 넣어준다.
하지만 객체지향 모델링의 문제점은 조회에서 발생한다.
객체 모델링 조회
SELECT M.*, T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
public Member find(String memberId) {
//SQL 실행
Member member = new Member();
//DB에서 조회한 회원 관련 정보를 모두 입력
Team team = new Team();
//DB에서 조회한 팀 관련 정보를 모두 입력
//회원과 팀 관계 설정
member.setTeam(team);
return member;
}
조인해서 가져온 회원과 팀 각각의 정보를 각각의 객체에 넣어주고, 마지막으로 setTeam(team)으로 연관관계 설정까지 개발자가 해줘야한다.
굉장히 번거롭다. SQL중심으로 설계하면 그냥 바로 맞는 필드에 때려넣으면 되는데, 구분해서 가져온 후 연관관계까지 설정해줘야한다.
따라서 보통 member랑 team 함께 조회할 경우 MemberTeam이라는 큰 클래스(DTO) 만들어서 응답값 일자로 넣는다. 그리고 객체하나로 반환하고 이런식으로 많이 한다.
객체 모델링, 자바 컬렉션에 관리
자바 컬렉션으로 관리한다하면, 객체지향적으로 설계하는 것이 좋아진다.
list.add(member);
Member member = list.get(memberId);
Team team = member.getTeam();
코드가 간단해진다.
객체 그래프 탐색
객체는 자유롭게 객체 그래프를 탐색할 수 있어야한다.

서로 참조가 있는 객체들은 자유롭게 해당 참조를 타고 조회 가능해야한다.
member.getTeam()
member.getOrder().getDelievery() 이런식으로
하지만, 처음 실행하는 SQL에 따라 탐색범위가 결정되버려서 위에 그림처럼 될 수 없다.
SELECT M.*, T.*
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
member.getTeam(); //OK
member.getOrder(); //null
처음 SQL에서 member랑 team만 가져온다. 따라서 oreder는 null값이 된다.
엔티티 신뢰 문제로 이어진다.
class MemberService {
public void process() {
Member member = memberDAO.find(memberId);
member.getTeam(); //???
member.getOrder().getDelievery(); //???
}
}
memberDAO를 통해 조회해온 member 엔티티에 Team과 Order, 그리고 Delievery라는 연관관계들 있지만, memberDAO에서 해당 데이터를 조회해왔는지 확실히 알지못하기 때문에 자유롭게 호출할 수 없다.
그렇다고해서 모든 객체를 미리 로딩할 수는 없다
member 조회할 때마다 모든 연관된 객체 다 끌고올 수도 없다.
따라서 대안으로 상황에 따라 동일한 회원 조회 메서드를 여러벌 생성한다.
memberDAO.getMember(); //Member만 조회
memberDAO.getMemberWithTeam(); //Member와 Team 조회
memberDAO.getMemberWithOrderWithDelievery(); //Member, Order, Delievery 조회
SQL을 직접 다루게 되면, 계층형 아키텍쳐에서 진정한 의미의 계층 분할이 어렵다.
String memberId = "100";
Member member1 = memberDAO.getMember(memberId);
Member member2 = memberDAO.getMember(memberId);
member1 == member2; //다르다
class MemberDAO {
public Member getMember(String memberId) {
String sql = "SELECT * FROM MEMBER WHERE MEMBER_ID = ?";
...
//JDBC API, SQL 실행
return new Member(...); //새로운 객체 생성해서 반환하니까 == 비교 당연히 다름
}
}
비교하기 - 자바 컬렉션에서 조회
String memberId = "100";
Member member1 = list.get(memberId);
Member member2 = list.get(memberId);
member1 == member2; //같다
자바 컬렉션에서 같은 key값으로 조회한 객체는 동일하다.
객체를 자바 컬렉션에 저장하듯이 DB에 저장할 수는 없을까?
자바 진영에서는 이러한 고민의 결과로 JPA(Java Persistence API)가 나옴