1. SQL 중심적인 개발의 문제점

💡 인프런의 김영한 선생님 강의를 정리한 글입니다.

객체 지향 언어와 관계형 데이터 베이스

객체 지향 언어를 이용한 애플리케이션은 보통 관계형 데이터 베이스에서 관리한다.

그러다 보니 SQL 중심적인 개발이 주를 이루게 된다. (CRUD → 지루한 코드를 무한 반복 함)

예를 들어 회원 객체를 만들었다면, 그에 해당하는 SQL을 짜게 되는데

만약 개발하다가 필드가 추가되면 짜놓은 SQL 쿼리들을 하나씩 다 수정해야 한다..

즉, SQL에 의존적인 개발을 피하기 어렵다.

또, 객체와 관계형 데이터 베이스 사이의 패러다임의 불일치가 발생한다.


🤔 객체를 어떤 저장소에 보관해야 할까?

객체를 보통 다음과 같은 4개의 저장소에 저장한다.

RDB, NoSQL, FILE 등이 있는데, 현실적으로 FILE에 넣으면 검색을 할 수 없다.

NoSQL은 대안이 될 수 있지만, 아직 메인이 아니다.

➡️ 현실적인 대안으로 관계형 데이터 베이스를 써야 한다.


🤣 객체를 SQL로 변환 해야 한다.

객체를 SQL로 바꿔서 RDB에 저장해야 하는데

이 객체를 SQL로 바꾸는 작업을 개발자가 하게 된다.. (개발자 = SQL Mapper..)


객체와 관계형 데이터 베이스의 차이

1. 상속

객체 → 상속 관계

관계형 데이터 베이스 → 슈퍼타입, 서브타입

관계형 데이터베이스의 경우, 예를들어 ALBUM을 저장하려면, ITEM과 ALBUM테이블에 저장할 쿼리 2개를 만들어야 한다.

삽입의 경우에는 크게 복잡하진 않지만, 조회의 경우는 다르다.

ALBUM을 조회하고 싶다면, ITEM과 ALBUM 테이블을 JOIN해서 ALBUM과 ITEM 각 객체에 맞게 데이터를 집어 넣어 줘야한다.

이렇게 객체가 상속 관계로 맵핑되어 있다면, 데이터 베이스에서 매번 여러 테이블을 JOIN하여 데이터를 가져와야 한다.

➡️ 결론 : DB에 저장할 객체에는 상속 관계를 쓰지 않는다.

 

반대로, 객체, 즉 자바의 컬렉션을 사용할 경우,

list.add(album);

Album album = list.get(albumId);

// 부모 타입으로 조회 후 다형성 활용
Item item = list.get(albumId);

➡️ list.get(albumId)으로, 앨범 아이디만으로 아이템을 조회 해올 수 있다. (다형성을 통해 부모 타입인 Item을 가져올 수 있다)


2. 연관 관계

객체 → 참조(reference)로 연관관계를 찾는다. ex) memger.getTeam()
테이블 → 외래키로 연관관계를 찾는다. ex) join on m.team_id = t.team_id

테이블은 멤버테이블에서 팀 테이블을, 반대로 팀 테이블에서 멤버테이블을 조회할 수 있음.(양방향 조회 가능)
반면, 객체는 멤버에서 팀으로 밖에 조회할 수 없다. (위 그림은 단방향 이기 때문. 추후 양방향 연관관계에 대해 배움)


객체를 테이블에 맞추어 모델링 하면 다음과 같다.

class Member {
    String id; // MEMBER_ID 컬럼 사용
    Long teamId; // TEAM_ID FK 컬럼 사용
    String username;// USERNAME 컬럼 사용
}
class Team {
    Long id; // TEAM_ID PK 사용
    String name; // NAME 컬럼 사용
}

멤버 객체에 팀 객체의 외래키를 가져오도록 모델링 하였음.

근데 위에서 객체는 참조로 연관관계를 맺는다고 정답을 말했다.
객체 지향적인 설계를 위해서는 멤버 객체에 팀 객체의 참조값을 가지는게 당연한 생각이다.
(그래야 member.getTeam()으로 연관관계를 찾아올 수 있다.)


객체 다운 모델링을 하면 다음과 같다.

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 컬럼 사용
}

다음과 같이 모델링하면 db에 값을 저장할 때 member 데이터와, 외래키 값을 저장해야 한다.
멤버 객체에는 팀의 참조값만 가지고 있기 떄문에, member.getTeam().getId()로 팀의 pk를 가져와서 저장하면 된다.

저장은 위 방식으로 해결이 가능함.

근데 또 조회의 경우에 문제가 생긴다.

 

 

예를들어,

class MemberService {
...
    public void process() {
        Member member = memberDAO.find(memberId);
        member.getTeam(); //???
        member.getOrder().getDelivery(); // ???
    }
}

다음과 같이 멤버의 값을 조회하고, 멤버가 속해있는 팀을 찾아 오는 비즈니스 로직이 있다고 생각해 보자.

객체는 원래 그래프 탐색이 가능해야 한다. → get을 통해 참조된 모든 객체를 탐색 할 수 있다.

하지만, 위 로직에서 memberDAO.find(memberId); 이 구문이 어떤 SQL을 날리는지 우리는 알지 못한다.
(memberDAO의 find 메서드를 구현한 사람만 안다..)

SQL이 실행된 순간 부터 조회해온 테이블의 범위가 정해져 있기 때문에, 멤버 객체가 모든 객체들을 get으로 탐색할 수 있다는 보장이 없다.

 

 

예) 처음 실행하는 SQL에 따라 탐색 범위 결정

SELECT M.*, T.* FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
member.getTeam(); //OK 
member.getOrder(); //null

참고 : Layerd-Architecture : 계층 간에는 신뢰가 존재해야 하는데, 위의 경우 Entity 간의 신뢰를 할 수 없다.
(물리적으로는 service, dao 계층이 나눠져 있지만, 논리적으로는 긴밀하게 엮여있기 때문이다.)
즉, 모든 객체를 미리 로딩할 수 없기 때문에 상황에 따라 조회 메서드를 여러개 만들어야만 한다.
➡️ 흔히 말하는 계층형 아키텍처에서, 진정한 의미의 계층 분할이 어려워 진다.

 


조회해온 값을 비교 할때도 문제가 생긴다.

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(...);
    }
}

SQL로 조회해온 값들을 결국 새로운 멤버 인스턴스를 반환 시키기 때문에 member1과 member2의 참조가 다르게 된다.

하지만 자바의 컬렉션에서 멤버를 조회한다고 생각하면

String memberId = "100";
Member member1 = list.get(memberId);
Member member2 = list.get(memberId);
member1 == member2; // 같다.

조회를 위한 id (key 값)의 같기 때문에 member1과 member2는 같은 객체이다.

결론 : 객체 답게 모델링 할 수록 SQL ↔️ 객체 맵핑 작업이 늘어난다.

객체를 자바의 컬렉션에 저장하듯이, 관계형 데이터베이스에 저장할 수 없을까? 라는 생각의 결과물로 JPA가 등장하게 됨.

'Java > 자바 ORM 표준 JPA 프로그래밍 - 기본편' 카테고리의 다른 글

5. 엔티티 매핑  (0) 2022.03.20
4. 영속성 관리 - 내부 동작 방식  (0) 2022.03.19
3. JPA 시작  (0) 2022.03.12
2. JPA란 무엇인가?  (0) 2022.02.20

댓글

Designed by JB FACTORY